Category Archives: Nonsense

Repository for the uncategorizable.

I’ve been using the FileZilla FTP client for many years and in that time have had only a few occasions where the application didn’t perform with the default settings.

One of those instances was yesterday, when I was trying to connect to my firm’s FTP site from an external network connection. From inside the office, using the internal IP address, FileZilla connected normally and displayed the contents of the root directory after I authenticated.

From outside the office, connecting via the hostname ftp.domain.com, FileZilla would connect normally and authenticate successfully, but it would not display the contents of the root directory. Instead, the server would send a “425 Can’t open data connection” message. FileZilla would then report “Error: Failed to retrieve directory listing”.

Here’s the complete conversation between the client and the server (names and IP addresses changed to protect the firm’s identity):

Status: Resolving address of ftp.domain.com
Status: Connecting to 38.98.xxx.xxx:21...
Status: Connection established, waiting for welcome message...
Response: 220-Microsoft FTP Service
Response: 220 Company Name
Command: USER ftp_username
Response: 331 Password required for ftp_username.
Command: PASS **********
Response: 230-Welcome to the Company Name FTP service.  Unauthorized use is strictly prohibited.
Response: 230 User ftp_username logged in.
Status:	Connected
Status:	Retrieving directory listing...
Command: PWD
Response: 257 "/" is current directory.
Command: TYPE I
Response: 200 Type set to I.
Command: PASV
Response: 227 Entering Passive Mode (192,168,0,114,13,156).
Status: Server sent passive reply with unroutable address. Using server address instead.
Command: LIST
Response: 425 Can't open data connection.
Error: Failed to retrieve directory listing
Response: 421 Timeout (120 seconds): closing control connection.
Error: Could not read from socket: ECONNRESET - Connection reset by peer
Error: Disconnected from server

The interesting thing, I thought, was that when the server agreed to use passive mode, it did so with a port on the internal IP address, which is unroutable from outside the network.

The fix is to use active mode

OK, if you’re reading this, you probably just want to know how to make it work. FileZilla uses passive mode by default, but due to the network configuration of certain servers, active mode is required to establish a data connection. A bit of background reading with some explanation is farther down.

In FileZilla, click on Edit | Settings.

Under Connection, click on FTP and choose Active as the Transfer Mode.

Under Connection, under FTP, click on Active mode and choose “Ask your operating system for the external IP address” (the default setting).

Under Connection, under FTP, click on Passive mode and choose “Fall back to active mode” (this is an optional setting).

What is the difference between active and passive mode?

According to the FileZilla wiki page on network configuration:

In passive mode, which is recommended (see below), the client sends the PASV command to the server, and the server responds with an address. The client then issues a command to transfer a file or to get a directory listing, and establishes a secondary connection to the address returned by the server.

In active mode, the client opens a socket on the local machine and tells its address to the server using the PORT command. Once the client issues a command to transfer a file or listing, the server will connect to the address provided by the client.

The difference, then, is which side gets to determine the address used during the connection. In passive mode, the server provides the address, while in active mode, the client provides the address.

Why do I need to use active mode?

You probably shouldn’t need to use active mode, and in fact, it requires more configuration by the user of the FTP client to use active mode.

In passive mode, the router and firewall on the server side need to be configured to accept and forward incoming connections. On the client side, however, only outgoing connections need to be allowed (which will already be the case most of the time).

Analogously, in active mode, the router and firewall on the client side need to be configured to accept and forward incoming connections. Only outgoing connections have to be allowed on the server side.

http://wiki.filezilla-project.org/Network_Configuration#Technical_background

So, it boils down to who’s going to be responsible for the NAT and firewall configuration. Using passive mode places the responsibility on the server side of the connection, while using active mode places it on the client side. Typically, the FTP server administrator should be better equipped to handle this responsibility than the average FTP client user.

Passive mode

In passive mode, the client has no control over what port the server chooses for the data connection. Therefore, in order to use passive mode, you’ll have to allow outgoing connections to all ports in your firewall.

Active mode

In active mode, the client opens a socket and waits for the server to establish the transfer connection.

http://wiki.filezilla-project.org/Network_Configuration#Setting_up_FileZilla_Client

I’m behind a NAT router and I’ve never had any problems with passive mode. On the other hand, I seem to be able to connect to all my sites without any problem with the client in active mode, too, and I haven’t had to open any ports in Windows Firewall or forward any ports on my router. So maybe active mode doesn’t require as much configuration as the wiki page leads me to believe. Or maybe I’m just getting lucky and I’ll eventually run into problems if I continue to run in active mode.

Why does the server respond with the local IP address?

The FileZilla people offer a a partial explanation for why I’m seeing the internal IP address when I connect using the hostname. Back in Settings, under Connection | FTP | Passive mode, is some support text that reads: Some misconfigured remote servers which are behind a router, may reply with their local IP address.

The wiki page is pretty good reading, and has some interesting stuff on NAT, but I think that I’ll offer this plain-language, local IP address explanation when troubleshooting FTP connections.

I was trying to create a bootable flash drive with Ubuntu 11.04 using the Universal USB Installer 1.8.6.3 utility from pendrivelinx.com on a Windows 7 64-bit machine with a 16 GB flash drive (mapped to G:), but I kept getting an error that the drive wouldn’t be bootable.

The message in the command line window read:

Execute: C:\Users\[username]\AppData\Local\Temp\[random].tmp\syslinuxnew.exe -maf G:
Syslinux Errors 1

A message box would then appear with the following warning:

Universal USB Installer 1.8.6.3 Setup

An error(1) occurred while executing syslinux.
Your USB drive won’t be bootable…
[OK]

When I opened a command prompt and ran syslinuxnew.exe -maf G:, the result was zero FAT sectors. When I ran syslinux.exe -maf G:, I got a much more informative message, or at least one that I could better understand: this doesn’t look like a valid FAT filesystem.

And of course, the flash drive wasn’t FAT32, it was NTFS. I had forgotten to format the drive as FAT32 before running the utility, but I also managed to not check the box next to “We will format G:\Drive as FAT32.” in the utility itself.

No wonder Google wasn’t returning any results when I searched this – who’s going to have missed properly formatting the drive not once but twice?

In the event that a quick format as FAT32 doesn’t work for you, you can try running a few diskpart commands in Windows to really thoroughly format a flash drive, including the MBR and partition table.

Update 1:59 PM 9/19/2011: Tier 3 support at Virgin Mobile was able to change my Beyond Talk Plan back to $25/month, which was the resolution I was looking for. Nice work, Tier 3.

12:26 PM 9/17/2011

I bought a Virgin Mobile Android phone on July 15, 2011, back when the least expensive plan was $25/month (a terrific deal, IMO). Today, I ported my T-Mobile phone number, but as a result, I was put on the current least expensive plan, which is $35/month (the included minutes and unlimited text, messaging, and data levels of the service are all unchanged). The cost of porting my number, which was only revealed after the port was successful, will be $10/month, to be paid in perpetuity.

The customer service rep that handled the actual porting didn’t seem to know what was going on. At one point, because he seemed so confused, I stopped and asked him point blank if porting numbers was something that happened very often. After the number was ported, I received the text message confirming the change, which noted that my plan was $35/month. The phone, which was supposed to start working after the port, wasn’t able to receive calls. I couldn’t even log into my account at virginmobileusa.com because I had a $0 balance, reportedly because hadn’t paid my $35 monthly bill yet (even though I’d just paid for another month at $25 two days earlier).

I called back, but the rep I reached this time couldn’t change my account back to $25/month, and put me on hold to speak with her supervisor. When she came back, she said the supervisor couldn’t convert my account to the $25/month plan either, and all they could do was credit me the additional $10 that the new plan would cost me this month.

She said that, had the first rep noted in the call that I had been on the $25 plan, this wouldn’t have happened. But because there was no such note, the system wasn’t allowing her to change to the $25 plan.

I told the rep that I would like to keep pursuing a different resolution, and asked for an email address. She gave me fraudalerts@virginmobileusa.com (which seems like a strange address for a department that handles non-fraudulent billing problems, but OK), so I sent the following message.

Date: Sat, 17 Sep 2011 12:25:00 -0500
To: fraudalerts@virginmobileusa.com
Subject: Porting my phone number resulted in my $25/month plan being cancelled…

Hello, there.

I have been a Virgin Mobile customer under the now discontinued $25/month plan for a few months. Before becoming a Virgin Mobile customer, I had a T-Mobile Prepaid – Pay As You Go plan. At the time I bought the Virgin Mobile phone, I still had a few hundred minutes on the T-Mobile plan that I wanted to use before porting that number to Virgin Mobile.

Virgin Mobile changed the plan pricing structure after I became a customer, increasing the price on the $25 plan to $35/month. When I ported the T-Mobile number, my Virgin Mobile account changed to the $35 plan. I wasn’t told at the time that my plan would change, and honestly, I would have stuck with the original Virgin Mobile phone number if I had been told that it would cost me $120/year to port my number.

I think it’s probably possible to activate a $25/month plan, even if the helpful phone support staff cannot do this. Someone, somewhere must have adminstrative access to do this.

Can you please provide contact information for the department that would be able to return my account to the $25/month plan, even if that means putting me back on a Virgin Mobile-assigned phone number?

If the porting of a number is going to cause a change to the account, and I’m not sure why this must be the case, it would be gracious to alert the customer.

Here’s my plan:
1. Try again to submit a ticket using the virginmobileusa.com web site (the first time, I got a page not found error: “The specified URL cannot be found”).
2. Call one more time.
3. Give Virgin Mobile 48 hours to respond to the email to fraudalerts email.
4. File a complaint with the BBB.

8:40 PM 9/17/2011

A few more thoughts:

Virgin Mobile seems to be treating this as a new account when it’s just a number port. I even got an “About Your Phone & Phone Number” email from Virgin Mobile that is identical to the email I received when I first became a customer back in July:

Hey OLIVER,

Thanks for joining Virgin Mobile! We know there are a lot of wireless options out there and we’re really glad you chose us.

Your Phone Number Is: (xxx) xxx-xxxx

Top-Up Now To Start Using Your Phone:
To start using your Virgin Mobile Service all you need to do is add money to your account. If you haven’t done that yet, click here to log in and do it now. Or, give us a call at 1-888-322-1122.

As soon as you’ve Topped-Up, you should be able to start using your phone. Access to Downloads and Voicemail can take up to 4 hours to come online, but usually it’s a lot sooner.

If you want to learn about your phone click here and then click on the Phone, Apps & More page to see additional information about your phone.

Stay Tuned:
We’ll be back in touch soon with some more info about your service. If you have any questions in the meantime, check out virginmobileusa.com or give us a call at 1-888-322-1122. Thanks again, and welcome aboard!
Virgin Mobile

At the bottom of the message is an email address that I hadn’t found when looking for ways to contact customer support: ourteam@virginmobileusa.com. I’ll be sending them a copy of my first email shortly.

Also, the FCC’s Guide to Portability doesn’t mention anything about whether a service provider can change your service on you during a port, but they do state that you can port your number at any time.

The FCC also has an online form for filing a complaint, so along with the BBB, this makes two avenues of recourse if Virgin Mobile won’t resolve this themselves.

11:53 PM 9/17/2011

Just for the record, before I became a customer, I wanted to be sure that the rates for existing customers wouldn’t increase on July 20, 2011. I emailed Virgin Mobile on 07/14/2011 at 10:02 PM, and this was their response (4 days later):

Response Via Email (Jennifer) 07/18/2011 12:54 AM
Hello Oliver,

Thanks for contacting Virgin Mobile Customer Care.

We are so glad to know that you want to become part of our Virgin Mobile family!

You have a great option to take advantage of, purchasing a Virgin Mobile phone that is compatible with our Beyond Talk plans because you cannot sign up for a monthly plan if you have not activated yet a phone, sorry about that! Remember that as of July 20th, 2011, new Virgin Mobile customers will be activated on the new plans while existing Beyond Talk customers will be able to stay on their current plans.

If you need additional assistance, feel free to respond to this email or contact us at 1-888-322-1122 (or *VM from your handset). You can reach us Monday through Sunday from 4am-9pm PST.

Thanks,

Kim
Virgin Mobile At Your Service
www.virginmobileusa.com

I’m pretty sure that I’ve got a good case here.

8:28 PM 9/18/2011

I received a response to my email to ourteam@virginmobileusa.com.

Response Via Email (Jose) 09/18/2011 02:22 PM
Hello Oliver,

Thanks for contacting Virgin Mobile Customer Care.

First let us extend our apologies for any inconvenience this has caused.

Virgin Mobile values each customer and is disappointed to know how you have stated your issue was handled.

Unfortunately, the $25 Beyond Talk Plan is no longer available and there is no way for us to get it active in your account. These rate changes affect new activations and plan changes in our system, and in order to process a Port In Request, the phone serial number needed to be free. That is the reason we needed to deactivate your old Virgin Mobile phone number.

Please accept our apologies for being unable to give you a different response, but this is the policy we are ruled by.

If you need additional assistance, feel free to let us know how we can assist further or contact us at 1-888-322-1122 (or *VM from your handset). You can reach us from Monday to Sunday from 4:00 am- 9:00 pm PST.

Thanks,

Heydi
Virgin Mobile At Your Service

Right off the bat, I think it’s unlikely that there isn’t some administrative override possible. While the $25 Beyond Talk Plan is no longer available, I suspect there is a way to charge my account $25/month. But let’s assume that changing the plan is not an option. Another resolution could be that Virgin Mobile credits me the difference between the $25 Beyond Talk Plan and whatever plan they want me to use. That can be as little as $10/month, or $120/year, for as long as I am a customer. This way I’m not incurring a cost for porting my number, and Virgin Mobile isn’t confronted with the hassle of making that administrative change to my account.

I don’t believe the average wireless customer could be expected to consider the porting of a phone number as a plan deactivation and a new plan activation.

I sent the following reply:

Hello there,

Thanks for writing back to me.

Unfortunately, the issue is not yet resolved to my satisfaction, as I still strongly feel that porting my number should not cost me $10/month for as long as I am a customer.

Now that the plan has been changed, however, there is still a way to resolve this to my satisfaction. Virgin Mobile can keep me on the $35 Beyond Talk Plan, and so avoid the problem of putting me back on the $25 Beyond Talk Plan, but then credit my account the difference each month.

I think that this is a fair and manageable way of handling the issue.

I’ll wait a day to hear back from my friends at ourteam@virginmobileusa.com and then go to the FCC and BBB.

12:30 PM 9/19/2011

I received a response from ourteam@virginmobileusa.com last night.

Response Via Email (Mariela Valenzuela) 09/18/2011 10:49 PM

Hello Oliver,

Thanks for contacting Virgin Mobile Customer Care.

Please accept my apologies on behalf of Virgin Mobile, our customers are highly valued and we are sorry to know that at this moment your experience has not been pleasant and easy.

Regarding your request, unfortunately we will not be able to process a $10 adjustment every month to cover your monthly charge. We are very sorry about that.

We understand your point of view and our main goal is your satisfaction, but our system cannot proceed against our terms of service. We are very sorry for any misunderstanding and inconvenience that you had regarding this issue.

If you need additional assistance, feel free to let us know how we cana ssist further or contact us at 1-888-322-1122 (or *86 from a Virgin Mobile handset). You can reach us Monday through Sunday from 4am-9pm PST.

Thanks & Best Regards,

Maryelah
Virgin Mobile At Your Service
www.virginmobileusa.com

So, it seems that it’s time to file a complaint with the FCC and the BBB. The FCC has a nifty online form for complaints (but it’s limited to 1000 characters), so I submitted the following.

Hello,

I became a Virgin Mobile USA mobile phone customer in July, 2011 under the $25/month plan (“$25 Beyond Talk”). Since then, the $25 Beyond Talk has been discontinued and a new plan, at $35/month, has replaced it for new customers. Existing customers remain on the $25/month plan.

I recently ported my T-Mobile number to my Virgin Mobile account. During the port, my $25/month account was cancelled and a new account was created on the $35/month plan. I was not told of this at the time by the CSR handling the porting and would have declined to port the number.

I have contacted Virgin Mobile in an attempt to resolve this problem, but they have only offered me a one-time $10 credit to my account. Virgin Mobile reports that they are unable to put me back on the $25/month plan, and are unwilling to credit me the difference of $10/month each month going forward.

Details of the correspondence are at //ardamis.com/2011/09/17/virgin-mobile-usa/

Thank you for your assistance.

After submitting that complaint, I received a reply to my email to fraudalerts, sent by Stephanie M from the email address Tier3@virginmobileusa.com. I had only asked fraudalerts for the contact information of a department that could help, and so didn’t provide my phone number or PIN in that email. The reply from Stephanie M was just a request for that information. I replied to Tier3@virginmobileusa.com with the phone number and PIN.

I think I’ll wait to see what comes of the FCC complaint and the Tier 3 investigation before going to the BBB.

1:59 PM 9/19/2011

Well, that was fast. Tier 3 came through with the fix that all other contacts at Virgin Mobile claimed was impossible. Stephanie M set my account to $25/month. Her email to me:

YOUR ACCOUNT HAS BEEN CREDITED 35.00 SO THAT I COULD TAKE OUT 25 .00 FOR THE
25 BEYOND TALK PLAN YOUR ACCOUNT CASH BALANCE IS 10.00

Thank you,
STEPHANIE M
Virgin Mobile Tier 3

I logged into my account at Virgin Mobile and confirmed that the price for my Beyond Talk plan is $25.00/month. I sent Stephanie a thank you.

Stephanie!

Oh my goodness! Were you really able to put my account back to $25/month?

You have no idea how many people have told me this was not possible.

Thank you very, very much.

I think this is the end of the story. I’ll have to try to contact the FCC and cancel the complaint.

A moment ago, a new email arrived:

Hey OLIVER,

Thanks for switching to our $25 Beyond Talk Plan.

For worry-free monthly service, make sure you’ve registered a payment method with us. Or, buy Top-Up cards to cover the cost of your monthly charge.

Manage Your Account The Easy Way.
To Top-Up, get downloads, and check your balance, log in at virginmobileusa.com. Just enter your phone number and Account PIN.

With Virgin Mobile, you’re in control. It’s just that simple.

Thanks, bye.
Virgin Mobile

Why do I even play Modern Warfare 2: Black Ops? I’m awful at it. I have something like a .49 K/D ratio and I’m almost always the worst guy on the squad.

If I was this bad at any other game, I would’t play it. But for some reason, I keep going back for more humiliation. I can’t figure it out. By all accounts, I should hate this game. I should put it away and never play it again. So why do I pick it up again, over and over?

I die alot

I’m too slow on the melee attack, which results in people appearing to run past me and then I get knifed. This is particularly weird, because I was awesome at melee in Halo.

I never win a face-to-face quick-draw contest. Maybe I sprint too much, or something, because it seems that the other guy can always raise his gun and shoot faster than I can.

The game likes to spawn me in front of more than one guy, too. Particularly on Crisis. Sometimes in the path of three guys.

My technique is weak

I really try to study the kill cams to find out how each guy beat me, but much of the time they’re shooting me in the foot or whatever. Hell, I can usually unload an entire clip into someone’s feet before they just casually finish reloading or whatever and then off me. It is frustrating, though, when the kill cam doesn’t quite jive with my recollection of the encounter. Like when I’m pretty sure I shot first, but the kill cam shows the other guy very obviously getting the jump on me.

I also can’t figure out how these guys finish a game with ridiculous stats, like 38/3. Guys like that look like they always know exactly where I am, from the Kill Cam. Maybe they just know the maps extremely well and can anticipate where someone ought to be? I saw one shared video of a guy who got 100 kills in a game, and he spent much of the time standing in the open, turning from side to side, shooting guys as they rounded a corner and ran up a hill.

Maybe I’m doing it all wrong. Maybe standing in the open is a genius strategy, but my gut tells me to find a place where I can protect my back with a claymore and shoot down a hallway or something. Or, if I decide to just always keep moving, I run the perimeter so that there is less opportunity to be ambushed. But neither of these tactics is going to get me 20 kills per game.

Like one dog waiting on another

Instead of going all lone-wolf all the time, I sometimes try to follow someone on my team in an attempt to combine our firepower. This seems to be a decent strategy on paper (and I sure get mowed down by multiple enemies enough to think that it’s effective), but more often than not, we’re both taken out by a grenade within about 15 seconds.

If I enter a room and see a teammate crouched down, gun pointed at the door, I typically figure he’ll be standing guard long enough for me to look out a window. The guy’s got my back, I figure. But no, I’ll get knifed in the kidney the moment I start looking down the street. It happens every time. Where’s the camaraderie, fellas?

Impossible

I get killed by these physics-defying grenade tosses that bounce in impossible ways, or fly half-way across the map and through the window to land at my feet, but I couldn’t get a grenade through a barn door. Chances are, my grenade will just bounce off a wall and come back to get me. At least the grenade physics part of the game is consistent with MW2. I probably have a 1 in 20 chance of successfully avoiding a grenade. I’d like to see stats on that.

A single napalm strike typically gets me more than once. I feel certain that I’ve actually spawned in the napalm.

Cover

I am forever trying to be sneaky and realistic, moving from cover to cover before looking around a wall or something. Usually, I’ll be seen before I locate my enemy and the cover will appear to be at least partly effective. I’ll get knicked a few times, but feel that I was very smart to have cover so close, then gracefully move back into the cover, then fall down and die. Are they shooting me through the wall each time? Because it sure feels like the game is just lagging and it’s decided that I’m already dead before I move behind the wall.

Even so, even with all the frustration and suckiness, I’m really looking forward to Modern Warfare 3. Plus, I heard they improved the completely lame and irritating slow-motion final kill cam stuff. Maybe now the guy doesn’t run past the cross hairs half a second before the blood splatter materializes out of thin air.

Update: I am just as bad at Modern Warfare 3.

Update 2015-01-02: About a month ago, in early December, 2014, Google announced that it was working on a new anti-spam API that is intended to replace the traditional CAPTCHA challenge as a method for humans to prove that they are not robots. This is very good news.
This week, I noticed that Akismet is adding a hidden input field to the comment form that contains a timestamp (although the plugin’s PHP puts the initial INPUT element within a P element set to DISPLAY:NONE, when the plugin’s JavaScript updates the value with the current timestamp, the INPUT element jumps outside of that P element). The injected code looks something like this:
<input type=”hidden” id=”ak_js” name=”ak_js” value=”1420256728989″>
I haven’t yet dug into the Akismet code to discover what it’s doing with the timestamp, but I’d be pleased if Akismet is attempting to differentiate humans from bots based on behavior.
Update 2015-01-10: To test the effectiveness of the current version of Akismet, I disabled the anti-spam plugin described in this post on 1/2/2015 and re-enabled it on 1/10/2015. In the span of 8 days, Akismet identified 1,153 spam comments and missed 15 more. These latest numbers continue to support my position that Akismet is not enough to stop spam comments.

In the endless battle against WordPress comment spam, I’ve developed and then refined a few different methods for preventing spam from getting to the database to begin with. My philosophy has always been that a human visitor and a spam bot behave differently (after all, the bots we’re dealing with are not Nexus-6 model androids here), and an effective spam-prevention method should be able to recognize the differences. I also have a dislike for CAPTCHA methods that require a human visitor to prove, via an intentionally difficult test, that they aren’t a bot. The ideal method, I feel, would be invisible to a human visitor, but still accurately identify comments submitted by bots.

Spam on ardamis.com in early 2012 - before and after

Spam on ardamis.com - before and after

A brief history of spam fighting

The most successful and simple method I found was a server-side system for reducing comment spam by using a handshake method involving timestamps on hidden form fields that I implemented in 2007. The general idea was that a bot would submit a comment more quickly than a human visitor, so if the comment was submitted too soon after the post page was loaded, the comment was rejected. A human caught in this trap would be able to click the Back button on the browser, wait a few seconds, and resubmit. This proved to be very effective on ardamis.com, cutting the number of spam comments intercepted by Akismet per day to nearly zero. For a long time, the only problem was that it required modifying a core WordPress file: wp-comments-post.php. Each time WordPress was updated, the core file was replaced. If I didn’t then go back and make my modifications again, I would lose the spam protection until I made the changes. As it became easier to update WordPress (via a single click in the admin panel) and I updated it more frequently, editing the core file became more of a nuisance.

A huge facepalm

When Google began weighting page load times as part of its ranking algorithm, I implemented the WP Super Cache caching plugin on ardamis.com and configured it to use .htaccess and mod_rewrite to serve cache files. Page load times certainly decreased, but the amount of spam detected by Akismet increased. After a while, I realized that this was because the spam bots were submitting comments from static, cached pages, and the timestamps on those pages, which had been generated server-side with PHP, were already minutes old when the page was requested. The form processing script, which normally rejects comments that are submitted too quickly to be written by a human visitor, happily accepted the timestamps. Even worse, a second function of my anti-spam method also rejected comments that were submitted 10 minutes or more after the page was loaded. Of course, most of the visitors were being served cached pages that were already more than 10 minutes old, so even legitimate comments were being rejected. Using PHP to generate my timestamps obviously was not going to work if I wanted to keep serving cached pages.

JavaScript to the rescue

Generating real-time timestamps on cached pages requires JavaScript. But instead of a reliable server clock setting the timestamp, the time is coming from the visitor’s system, which can’t be trusted to be accurate. Merely changing the comment form to use JavaScript to generate the first timestamp wouldn’t work, because verifying a timestamp generated on the client-side against one generated server-side would be disastrous.

Replacing the PHP-generated timestamps with JavaScript-generated timestamps would require substantial changes to the system.

Traditional client-side form validation using JavaScript happens when the form is submitted. If the validation fails, the form is not submitted, and the visitor typically gets an alert with suggestions on how to make the form acceptable. If the validation passes, the form submission continues without bothering the visitor. To get our two timestamps, we can generate a first timestamp when the page loads and compare it to a second timestamp generated when the form is submitted. If the visitor submits the form too quickly, we can display an alert showing the number of seconds remaining until the form can be successfully submitted. This client-side validation should hopefully be invisible to most visitors who choose to leave comments, but at the very least, far less irritating than a CAPTCHA system.

It took me two tries to get it right, but I’m going to discuss the less successful method first to point out its flaws.

Method One (not good enough)

Here’s how the original system flowed.

  1. Generate a first JS timestamp when the page is loaded.
  2. Generate a second JS timestamp when the form is submitted.
  3. Before the form contents are sent to the server, compare the two timestamps, and if enough time has passed, write a pre-determined passcode to a hidden INPUT element, then submit the form.
  4. After the form contents are sent to the server, use server-side logic to verify that the passcode is present and valid.

The problem was that it seemed that certain bots could parse JavaScript enough to drop the pre-determined passcode into the hidden form field before submitting the form, circumventing the timestamps completely and defeating the system.

Because the timestamps were only compared on the client-side, it also failed to adhere to one of the basic tenants of form validation – that the input must be checked on both the client-side and the server-side.

Method Two (better)

Rather than having the server-side validation be merely a check to confirm that the passcode is present, method two compares the timestamps a second time on the server side. Instead of a single hidden input, we now have two – one for each timestamp. This is intended to prevent a bot from figuring out the ultimate validation mechanism by simply parsing the JavaScript. Finally, the hidden fields are not in the HTML of the page when it’s sent to the browser, but are added to the form via jQuery, which makes it easier to implement and may act as another layer of obfuscation.

  1. Generate a first JS timestamp when the page is loaded and write it to a hidden form field.
  2. Generate a second JS timestamp when the form is submitted and write it to a hidden form field.
  3. Before the form contents are sent to the server, compare the two timestamps, and if enough time has passed, submit the form (client-side validation).
  4. On the form processing page, use server-side logic to compare the timestamps a second time (server-side validation).

This timestamp handshake works more like it did in the proven-effective server-side-only method. We still have to pass something from the comment form to the processing script, but it’s not too obvious from the HTML what is being done with it. Furthermore, even if a bot suspects that the timestamps are being compared, there is no telling from the HTML what the threshold is for distinguishing a valid comment from one that is invalid. (The JavaScript could be parsed by a bot, but the server-side check cannot be, making it possible to require a slightly longer amount of time to elapse in order to pass the server-side check.)

The same downside plagued me

For a long time, far longer than I care to admit, I stubbornly continued to modify the core file wp-comments-post.php to provide the server-side processing. But creating the timestamps and parsing them with a plug-in turned out to be a simple matter of two functions, and in June of 2013 I finally got around to doing it the right way.

The code

The plugin, in all its simplicity, is only 100 lines. Just copy this code into a text editor, save it as a .php file (the name isn’t important) and upload it to the /wp-content/plugins directory and activate it. Feel free to edit it however you like to suit your needs.

<?php

/*
Plugin Name: Timestamp Comment Filter
Plugin URI: //ardamis.com/2011/08/27/a-cache-proof-method-for-reducing-comment-spam/
Description: This plugin measures the amount of time between when the post page loads and the comment is submitted, then rejects any comment that was submitted faster than a human probably would or could.
Version: 0.1
Author: Oliver Baty
Author URI: //ardamis.com

    Copyright 2013  Oliver Baty  (email : obbaty@gmail.com)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

// http://wordpress.stackexchange.com/questions/6723/how-to-add-a-policy-text-just-before-the-comments
function ard_add_javascript(){

	?>
	
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    ardGenTS1();
});
 
function ardGenTS1() {
    // prepare the form
    $('#commentform').append('<input type="hidden" name="ardTS1" id="ardTS1" value="1" />');
    $('#commentform').append('<input type="hidden" name="ardTS2" id="ardTS2" value="1" />');
    $('#commentform').attr('onsubmit', 'return validate()');
    // set a first timestamp when the page loads
    var ardTS1 = (new Date).getTime();
    document.getElementById("ardTS1").value = ardTS1;
}
 
function validate() {
    // read the first timestamp
    var ardTS1 = document.getElementById("ardTS1").value;
//  alert ('ardTS1: ' + ardTS1);
    // generate the second timestamp
    var ardTS2 = (new Date).getTime();
    document.getElementById("ardTS2").value = ardTS2;
//  alert ('ardTS2: ' + document.getElementById("ardTS2").value);
    // find the difference
    var diff = ardTS2 - ardTS1;
    var elapsed = Math.round(diff / 1000);
    var remaining = 10 - elapsed;
//  alert ('diff: ' + diff + '\n\n elapsed:' + elapsed);
    // check whether enough time has elapsed
    if (diff > 10000) {
        // submit the form
        return true;
    }else{
        // display an alert if the form is submitted within 10 seconds
        alert("This site is protected by an anti-spam feature that requires 10 seconds to have elapsed between the page load and the form submission. \n\n Please close this alert window.  The form may be resubmitted successfully in " + remaining + " seconds.");
        // prevent the form from being submitted
        return false;
    }
}
</script>
	
	<?php
}

add_action('comment_form_before','ard_add_javascript');

// http://wordpress.stackexchange.com/questions/89236/disable-wordpress-comments-api
function ard_parse_timestamps(){

	// Set up the elapsed time, in miliseconds, that is the threshold for determining whether a comment was submitted by a human
	$intThreshold = 10000;
	
	// Set up a message to be displayed if the comment is blocked
	$strMessage = '<strong>ERROR</strong>:  this site uses JavaScript validation to reduce comment spam by rejecting comments that appear to be submitted by an automated method.  Either your browser has JavaScript disabled or the comment appeared to be submitted by a bot.';
	
	$ardTS1 = ( isset($_POST['ardTS1']) ) ? trim($_POST['ardTS1']) : 1;
	$ardTS2 = ( isset($_POST['ardTS2']) ) ? trim($_POST['ardTS2']) : 2;
	$ardTS = $ardTS2 - $ardTS1;
	 
	if ( $ardTS < $intThreshold ) {
	// If the difference of the timestamps is not more than 10 seconds, exit
		wp_die( __($strMessage) );
	}
}
add_action('pre_comment_on_post', 'ard_parse_timestamps');

?>

That’s it. Not so bad, right?

Final thoughts

The screen-shot at the beginning of the post shows the number of spam comments submitted to ardamis.com and detected by Akismet each day from the end of January, 2012, to the beginning of March, 2012. The dramatic drop-off around Jan 20 was when I implemented the method described in this post. The flare-up around Feb 20 was when I updated WordPress and forgot to replace the modified core file for about a week, illustrating one of the hazards of changing core files.

If you would rather not add any hidden form fields to the comment form, you could consider appending the two timestamps to the end of the comment_post_ID field. Because its contents are cast as an integer in wp-comments-post.php when value of the $comment_post_ID variable is set, WordPress won’t be bothered by the extra data at the end of the field, so long as the post ID comes first and is followed by a space. You could then just explode the contents of the comment_post_ID field on the space character, then compare the last two elements of the array.

If you don’t object to meddling with a core file in order to obtain a little extra protection, you can rename the wp-comments-post.php file and change the path in the comment form’s action attribute. I’ve posted logs showing that some bots just try to post spam directly to the wp-comments-post.php file, so renaming that file is an easy way to cut down on spam. Just remember to come back and delete the wp-comments-post.php file each time you update WordPress.

We have been using I-GO car sharing for a few months now, since we sold the Volvo Cross Country (which I loved) to cut down on our monthly expenses. With the car loan, parking, gas, maintenance, and insurance, we were paying around $400 a month, and because we both take public transportation whenever possible, we were using it only on the weekends for shopping or trips to the zoo or whatever. It just didn’t make sense, financially or practically, to own a car.

We were sure that I-GO would save us money, but we weren’t sure we could give up the freedom and independence that comes with ownership. As it turns out, we could, and with a combination of renting from Budget or Hertz for the longer trips and I-GO for the quicker ones, we found we could save some money without too much sacrifice.

But, we were basing our expectations for I-GO on our experiences with renting from businesses like Enterprise, and a shared car is not the same as a rented car. I-GO would do well to close some of these gaps.

For one, when you rent from a company like Enterprise, you can expect that the car has been recently cleaned, inside and out, and the tank is full. The regular maintenance, like tire pressure, has been taken care of, and you won’t get in to discover the check engine light on. You can also expect to find the owner’s manual in the glove compartment. This is not the case for car sharing. You are basically borrowing a stranger’s car for a few hours, and very few people are going to care to wash it and fill it up when they are under no obligation to do so. So you tend to find yourself climbing into a car that has someone else’s crumbs in the back seat and is nearly out of gas. Just how to turn on the AC, or the headlights, or figuring out what that light on the dashboard means, is left to your ingenuity and curiosity, as so far none of the car’s I’ve used have come with an owner’s manual.

Both the I-GO and the rental cars are generally quite new or only a few years old, which is nice. The last I-GO car I drove had only 500 miles on it, while the last rental had 2000.

I-GO cars come with a fleet gas card, so you don’t have to pay for gas yourself. But, because you are generally paying by the hour, you pay for the time it takes to gas up.

You also don’t have to wait in line to pick up or drop off the car, and there is no paperwork after the initial sign-up. This, to me, is a huge advantage, as the process of renting a car, even if you reserve it online, still seems to take half-an-hour or more and involves signing papers. Scheduling a time to borrow an I-GO car takes about 4 minutes and is done entirely online. It’s totally self-serve and the cars are available 24-7, so you’re not stuck waiting until an office opens on Monday morning to return a car.

Insurance is included in the I-GO cost; not so for rentals. With rentals, you can waive the insurance if you carry it yourself, but I-GO means you can cancel your insurance policy (with the understanding that you’ll have to then buy insurance when renting).

Because you’re typically paying by the hour (or half-hour) for I-GO, vs by the day or weekend with a rental, you do have a sense that you’re not getting your money’s worth when the car is sitting in the lot. So it’s not ideal for trips to the zoo, or other places where you park and leave the car for an extended amount of time. It’s best when you need to get some place, grab something, and zip back.

All-in-all, I-GO is pretty great. If they could come up with a small incentive to encourage people to wash and gas up, so that it felt like the cars were just-for-you and ready to go, it would be even better.

I would like to be asked to complete a survey after each rental that encourages me to report on the condition of the vehicle.

The only other thing that bothers me, and it’s not a big deal, is the bumper stickers on the cars identifying them as I-GO vehicles. I realize that it’s helpful advertising, and I’m not embarrassed or ashamed to be driving one, but the stickers are tacky-looking. More professional-looking signage, maybe a tasteful and understated sticker like you would see on a Mercedes courtesy car, or what they show on the I-GO home page, would be nice.

Oh, and we chose I-GO over Zipcar because I-GO is a Chicago non-profit, and we like to support the little guy when we can.

Overview of classes and objects

Objects are the building blocks of the application (ie: the workers in a factory)
Classes can be thought of as blueprints for the objects. Classes describe the objects, which are created in memory.
So, the programmer writes the classes and the PHP interpreter creates the objects from the classes.

A class may contain both variables and functions.
A variable inside a class is called a property.
A function inside a class is called a method.

Instantiation

To create an object, you instantiate a class (you create an instance of the class as an object).
For example, if we have a class named ‘person’ and want to instantiate it as the variable $oliver:

$oliver = new person();

The variable $oliver is referred to as the ‘handle’.

Accessing properties and methods

To access the properties and methods of a class, we use the object’s handle, followed by the arrow operator “->”.
For example, if our class has a method ‘get_name’, we can echo that to the page with:

echo $oliver->get_name();

Note that there are no single or double quotes used in instantiating a class or accessing properties and methods of a class.

Constructors

A class may have a special method called a constructor. The constructor method is called automatically when the object is instantiated.
The constructor method begins with two underscores and the word ‘construct’:

function __construct($variable) { }

One can pass values to the constructor method by providing arguments after the class name.
For example, to pass the name “John Doe” to the constructor method in the ‘person’ class:

$john = new person("John Doe");

! If a constructor exists and expects arguments, you must instantiate the class with the arguments expected by the constructor.

Access modifiers and visibility declarations

Properties must, and methods may, have one of three access modifiers (visibility declarations): public, protected, and private.
Public: can be accessed from outside the class, eg: $myclass->secret_variable;
Protected: can be accessed within the class and by classes derived from the class
Private: can be accessed only within the class

Declaring a property with var makes the property public.

Methods declared without an explicit access modifier are considered public.

! If you call a protected method from outside the class, any PHP output before the call is still processed, but you get an error message when the interpreter gets to that call:

Fatal error: Call to protected method...

Inheritance

Inheritance allows a child class to be created from a parent class, whereby the child has all of the public and protected properties and methods of the parent.

A child class extends a parent class:

class employee extends person {
}

A child class can redefine/override/replace a method in the parent class by reusing the method name.

! A child class’s method’s access modifier can not be more restrictive than that of the parent class. For example, if the parent class has a public set_name() method and the child class’s set_name() method is protected, the class itself will generate a fatal error, and no prior PHP output will be rendered. (In the error below, employee is the child class to person):

Fatal error: Access level to employee::set_name() must be public (as in class person) in E:xampphtdocstesteroopclass_lib.php on line 38

To differentiate between a method in a parent class vs the method as redefined in a child class, one must specifically name the class that contains the method you want to call using the scope resolution operator (::):

person::set_name($new_name);

The scope resolution operator allows access to static, constant, and overridden properties or methods of a class, generally, a parent class. This would be done inside the child class, after redefining a parent’s method of the same name.

It’s also possible to use ‘parent’ to refer to the child’s parent class:

parent::set_name($new_name);

(I’m still a bit vague on this and am looking for examples of situations in which this would be used.)

Classes inside classes

Just as it’s possible to instantiate a class and use the object in a view file, it’s possible to instantiate an object and call its methods from inside another class.

Static properties and methods

Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).

Resources
http://us2.php.net/manual/en/language.oop5.php
http://net.tutsplus.com/tutorials/php/oop-in-php/
http://www.phpfreaks.com/tutorial/oo-php-part-1-oop-in-full-effect
http://www.killerphp.com/tutorials/object-oriented-php/

The other day, I needed to extract a 7 GB zip file containing a VMware virtual machine onto the hard drive of a nearly stock 64-bit Windows 7 Professional machine. Because this machine did not have a third-party compression utility installed, I tried to extract it using Windows’ native zip utility, called Compressed Folders.

This failed with a pretty neat error.

You need an additional 5.99 PB to copy these files.

As you can see in the screenshot above, Windows reported that…

Copy Folder

There is not enough space on Local Disk. You need an additional 5.99 PB to copy these files.

Local Disk
Space free: 125 GB
Total size: 232 GB

[Try Again] [Cancel]

I found the 5.99 petabyte requirement pretty amusing, but I was in a hurry, so I downloaded the excellent 7-Zip, unpacked the file, and set about building the vm.

I had meant to write a post about the error message, but some time passed and I forgot all about it. Then, about three weeks later, someone else in the department tried to extract a copy of the file on a 32-bit Windows XP Professional machine and got the same error. At that point, I had to investigate.

The Compressed Folders native Windows utility seemed to be unable to accurately calculate the free space needed to extract the file. The file was admittedly pretty large, but was size the only reason?

According to the Wikipedia page on ZIP files, there are a number of known limitations of Compressed Folders.

ZIP64, AES Encryption, split or spanned archives, and Unicode entry encoding are not known to be readable or writable by the Compressed Folders feature in Windows XP or Windows Vista.

http://en.wikipedia.org/wiki/ZIP_(file_format)#Windows_compressed_folders

None of these things applied to my file, but I found a rather telling and simultaneously ambiguous (go figure) KB article at Microsoft Support: Compressed folder becomes corrupted when larger than 2 gigabytes.

According to various threads, the popular theory is that the problem stems from size limitations on compressed files. Windows Vista and later have a 4 GB limit (compressed and uncompressed size), while XP has a 2 GB limit.

Strangely, the same error appears before a copy process when the OS encounters a file that exceeds its maximum individual file size, which I can understand, but find a bit confusing in the context of a zip file. Certainly, both Windows 7 and XP (NTFS) were able to handle the file to begin with, and only had a problem when decompressing it.

My best guess is that the file was created using the Compressed Folders feature on XP. The file exceeded the maximum size limit for that version of Windows, but due to the bug described in MS KB article 301325, the file was created anyway using 32-bit headers. When the file was later opened by Compressed Folders, the 64-bit headers were read (as a file of that size would naturally use 64-bit headers), but that information was garbage, preventing Windows from accurately calculating the space required to extract.

If anyone has a more complete understanding of the cause of this error, please leave me a comment.

Back in May of 2011, the Xbox.com forums were redesigned. The old forum’s content was transferred to a new subdomain at http://forumsarchive.xbox.com/ and left to rot.

What happened to all the stuff in the “old” forums?

For a limited time, all your posts from the previous version of the forums live on forumsarchive.xbox.com (will be available shortly after the new forums have gone live). They are available for you to go grab any FAQs, walkthroughs, and other valuable posts that you created, so you can repost them in the new forums.

http://forums.xbox.com/xbox_forums/forum_faq/f/6/p/3058/19910.aspx

That isn’t quite true, as I’ve found links in posts on ardamis.com to at least one thread that I’d started on the old forum that is missing from the archive, so there has obviously been some culling happening.

I suspect that not only were countless useful threads simply abandoned or even deleted, but probably millions of inbound links to xbox.com were left to 404.

Instead of redirecting all of the links to the old forum threads, visitors following those links now see an ugly IIS server error message.

Server Error in ‘/’ Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Requested URL: /31685953/ShowPost.aspx

It’s stunning, actually, how poorly this transition was handled, and I’m not alone in thinking that. There are even threads on the new forum about how much better the old one was. I cannot picture any metric by which improvement is measured that would indicate this change was successful. And I would love to know how the decision was made to let tons of inbound links 404. Who on earth would allow this to happen to their site?

One of my most popular articles at ardamis.com was a description of the slow death of my Xbox 360 at the hands of FFXIII, which thankfully didn’t link to the forum threads that it referenced for support. All those threads on how either a) Final Fantasy XIII broke dozens of Xbox 360s, or b) dozens of Xbox 360s just happened to break as people were playing Final Fantasy XIII, disappeared. But I’ve begun a new one, for posterity (and not because I still play the game, which I found to be a huge disappointment). So, to keep the flame of discontent burning, here’s the link to the new thread on Final Fantasy XIII freezing on Xbox 360.

On the upside, a quick look at the HTML of the new pages suggests that the links are not nofollowed, which is something else I found interesting about the old forums.

Q: Just how quickly does Googlebot visit a page after it is linked to from a post on blogspot.com?
A: Pretty darn quickly.

I am curious about just what data is being passed to pages by user-agents. To try to gather some of this data, I created a test page at Aleph Studios. This page records the keys and values of the $_GET, $_POST, and $_COOKIE arrays, along with the values that belong to the keys starting with HTTP_ from the $_SERVER array, and the value of $_SERVER[‘REQUEST_TIME’]. It bundles all this up into an email and sends it to me each time the page is accessed.

In order to get this page into Google, I posted a link to it on my throwaway blog at Aleph Studios on Blogger. The timestamp of that post is 9:13 pm. The email from the page as triggered by Googlebot is timestamped 9:14 pm. That’s pretty slick.

The HTTP headers sent by Googlebot and recorded by the page are:

HTTP_ACCEPT = */*
HTTP_ACCEPT_ENCODING = gzip,deflate
HTTP_CONNECTION = Keep-alive
HTTP_FROM = googlebot(at)googlebot.com
HTTP_HOST = alephstudios.com
HTTP_USER_AGENT = Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

The page’s filename, title tag, and H1 tag are all “WvVdWfwgMcmypDqv7t”, so it’ll be easy to find in Google later. As I’ve observed in the past, within 20 minutes, the page on blogspot.com containing the string shows up in Google for a search on the string.

New pages don’t really take twenty minutes to show up in Google, but I don’t check Google very quickly after hitting the Publish button. The fastest I’ve personally witnessed a new page on ardamis.com appearing in Google was under 4 minutes.