Tim

Footprints in the snow of a warped mind

Development

Where to find me

Flickr Icon  Twitter Icon  Linked In Icon  FaceBook Icon  Windows Live Alerts Butterfly  RSS 2.0 

Business Protection by Crisis Cover

Tag Cloud

AJAX (4) Analysis (1) ASP (6) ASP.Net (56) Error Reporting (4) Web Service (2) WSDL (1) Atlas (2) Born In The Barn (1) Business (85) Business Start-up Advice (28) Client (16) Expanding Your Business (20) Recruitment (1) C# (20) Canoeing (4) Canoe Racing (5) Cheshire Ring Race (5) Racing (2) Training (4) CIMA (1) Cisco (1) 7970G (1) CMS (1) Code Management (1) Cohorts (1) Commerce4Umbraco (1) Content (1) Content Management (1) Content Management System (1) CSS (3) dasBlog (5) DDD (1) Design (10) Icons (1) Development (21) eCommerce (8) Employment (2) General (39) Christmas (6) Fun and Games (11) Internet (22) Random (46) RX-8 (8) Helpful Script (3) Home Cinema (2) Hosting (2) HTML (1) IIS (11) iPhone (1) JavaScript (4) jQuery (1) Marketing (6) Email (1) Multipack (1) MVC (1) Networking (3) Nintendo (1) Nuget (1) OS Commerce (1) Payment (1) Photography (1) PHP (1) PowerShell (2) Press Release (1) Productivity (2) Random Thought (1) Security (2) SEO (5) Server Maintenance (6) Server Management (11) Social Media (2) Social Networking (3) Experiment (1) Software (10) Office (5) Visual Studio (13) Windows (4) Vista (1) SQL (8) SQL Server (19) Statistics (1) Stored Procedure (1) TeaCommerce (1) Testing (2) The Site Doctor (124) Turnover Challenge (1) Twitter (3) uCommerce (9) Umbraco (29) 2009 (1) 2011 (1) Web Development (65) WebDD (33) Wii (1) XSLT (1)

Blog Archive

Search

<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

Recent Comments

Blog Archive

Various Links

Blogs I Read

[Feed] Google Blog
Official Google Webmaster Central Blog
[Feed] Matt Cutts
Gadgets, Google, and SEO
[Feed] Ol' Deano's Blog
My mate Dean's blog on my space, equally as random as mine but not off on as much of a tangent!
[Feed] Sam's Blog
Sam is one of my younger brothers studying Product Design and Manufacture at Loughborough, this is his blog :) Enjoy!

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

newtelligence dasBlog 2.2.8279.16125

Send mail to the author(s) Email Me (Tim Gaunt)

© 2012 Tim Gaunt.

Sign In

# Friday, October 28, 2011

Umbraco developers - remember to disable the umbDebug settings when you go live

Friday, October 28, 2011 12:05:41 PM (GMT Daylight Time, UTC+01:00)

Recently I've noticed a growing number of Umbraco developers forgetting to disable the Umbraco debug settings before going live. We all fall foul of this from time to time but it is a security loophole that you can patch incredibly easily.

If you're not familiar with the helpful debugging querystring parameters of umbDebug and umbDebugShowTrace they basically show you the ASP.Net trace output and highlight the various macros used on the page -there's also a useful toggle debugging in Umbraco bookmarklet on cpalm.dk.

Why you should disable trace

If you try it out on your site which has debugging enabled you'll get all sorts of helpful information output to the page including where your website is installed -all very helpful and interesting to hackers. It also identifies your site as an Umbraco site very quickly -again something you would want to avoid if at all possible.

How to disable the debug settings via the web.config

Umbraco helpfully has a built in flag in the web.config appSettings section which allows you to effortlessly toggle the debuging features on/off. To turn it off, search for "umbracoDebugMode" in your web.config and if it's set to "true", change it to false.

<add key="umbracoDebugMode" value="true" />

Should be:

<add key="umbracoDebugMode" value="false" />

For good measure you should also change ASP.Net's built in debug flag:

<compilation defaultLanguage="c#" debug="true" batch="false" targetFramework="4.0">

Should be:

<compilation defaultLanguage="c#" debug="false" batch="false" targetFramework="4.0">

Disable it using UrlRewriting.config

If you prefer the belts and braces method, you can add a rule to your UrlRewriting.config to redirect the user everytime the url includes something that looks suspicious. To do this, just add the following rewrites to your UrlRewriting.config (or replace it completely if you don't have any rules):

<urlrewritingnet xmlns="http://www.urlrewriting.net/schemas/config/2006/07"> 
          <rewrites> 
                    <add name="nodebugaspx" 
                        virtualUrl="(.*).aspx.*umbDebug.*" 
                        rewriteUrlParameter="IncludeQueryStringForRewrite" 
                        redirect="Application" 
                        destinationUrl="~$1.aspx" 
                        ignoreCase="true" />

                    <add name="nodebug" 
                        virtualUrl="(.*).*umbDebug.*" 
                        rewriteUrlParameter="IncludeQueryStringForRewrite" 
                        redirect="Application" 
                        destinationUrl="~$1" 
                        ignoreCase="true" /> 
          </rewrites> 
</urlrewritingnet> 
 

Don't forget to follow me on Twitter.

# Thursday, October 13, 2011

Estimating the real value of source code

Thursday, October 13, 2011 12:16:11 PM (GMT Daylight Time, UTC+01:00)

ThinkBeforeYouActCodeGradientIf you run a software development company of virtually any size, you've no doubt been asked/bullied at some point for the source code; sometimes it's even stipulated as a requirement of the contract.

At The Site Doctor we don't tend to quibble over the source code (especially not for standard websites at least) and that's mainly because we know that the value of what we do isn't in the files of code themselves; instead the value is in our knowledge of you, your product, your requirements and our past experiences in our respective areas of expertise.

Putting to one side for a moment the knowledge gap (this can be filled over time/with enough resources), depending on your future plans, getting access to the source may not be the holy grail you think it is. If you are actively developing your project on an on-going basis (you should be), consideration will need to be given to how you ensure your copy is up to date. We have systems to handle this (called source control) but you have to question whether the additional time required to learn and manage the various processes are of real benefit to you.

There are a few instances however where having access to the source code is definitely worth it. Have you for example got a contingency plan in place for if your supplier was to no longer exist? What would you do and how would you cope if the development company was no longer around? In these instances, having a copy of the source -or more importantly knowing how you can get access to the up-to-date copy is very important.

How can I quantify the worth of the source code to me?

As with many scenarios like this, there's not really a "one solution fits all" answer however after a little internal discussion we came up with the following:

Value of Source Considerations
High
  • Was the system completely bespoke?
  • Is it integral to your day-to-day operation?
  • Is it your only source of income?
Medium
  • Although integral to your business, you have a copy of the software in a usable form and it doesn't change regularly.
  • The system offers "standard" functionality which can be replicated with relative ease should it be required e.g. e-commerce functionality.
Low
  • The system is something generic, does not need to be changed
  • You have control over the aspects that you need e.g. it's a website with a content management system

Is it worth getting the source code as a client?

Yes; but I would consider the message it's giving to your developers. If you ask for it at the beginning of the contract then there shouldn't be a problem but bringing it up after delivery might leave the developers wondering what your motive is (even if it is totally innocent).

Should I give the source code to my client?

Yes; unless you've clearly stipulated otherwise to the client from the start for some reason e.g. to reduce project costs. You should always write your code in a way that is readable to others anyway and knowing that you might at anytime be offering up the source code will encourage you to keep it that little bit leaner.

How do you handle source code with your clients?

To handle a scenario in which The Site Doctor no longer exists (whether it's because we've gone into administration or we're all hit by a meteor), we use Crisis Cover; an online information storage system that securely stores all the information our clients would need if we were no longer around. Crisis Cover then checks that we're still around and if not, distributes the information to the designated contacts.

If you've not already got some form of contingency plan in place I urge you to set something up now whether it's a service like Crisis Cover, Excel or paper!

In closing I would definitely promote the attitude we have at The Site Doctor in that it's better to build long-term partnerships but you should still have some disaster contingency plan in place.

 

Don't forget to follow me on Twitter.

# Friday, September 02, 2011

Nuget server on IIS6 returns 404 when downloading package after upgrade

Friday, September 02, 2011 8:03:30 AM (GMT Daylight Time, UTC+01:00)

Nuget-Returns-404-Manager-ErrorWe updated our nuget server today and ran into a problem where regardless of package selected or whether it's through the nuget package manager or the nuget package explorer, the server returns 404 (File Not Found).

Nuget-Returns-404-Explorer-Error

What was odd about this was that the packages exist and the feed was valid:

Nuget-Returns-404-Manager

There are a couple of comments about this online e.g.: Codeplex Discussion 246387 but nothing helped.  It took a while to work out that it was caused by a slight change to the way the nuget server makes it's calls. Comparing the IIS logs between the old and new version of nuget server, the previous version of nuget server would redirect the user directly to the nupkg file:

2011-04-21 08:47:46 W3SVC1759424837 192.168.1.1 GET /Packages/TheSiteDoctor.2.0.235.68.nupkg - 80 - 192.168.1.2 Package-Installer/1.2.20325.9034+(Microsoft+Windows+NT+6.1.7601+Service+Pack+1) 200 0 0

On the new one however, it passes the various requests through a new MVC route "download":

2011-09-01 11:31:16 W3SVC1759424837 192.168.1.1 GET /download/TheSiteDoctor/2.0.235.68 - 80 - 192.168.1.2 Package-Installer/1.2.20325.9034+(Microsoft+Windows+NT+6.1.7601+Service+Pack+1) 404 0 3

This is fine if your nuget server is running on IIS7, it will "just work". However if you're running IIS6 you'll need to make one additional change which is mapping all request through the aspnet_isapi.dll (a wildcard mapping). This is easy enough:

  1. 1. Open the site's properties in IIS6
  2. 2. Navigate to the "Home Directory" tab
  3. 3. Click the "Configuration" button:
    Nuget-Returns-404-Explorer-IIS
  4. This will then open the "Application Configuration" window:
    Nuget-Returns-404-Explorer-IIS-Configuration
  5. Now you'll need to add the aspnet_isapi.dll mapping, the path of this will depend on the whether you're running Windox 64bit or not:
    32bit Framework: c:\windows\microsoft.net\framework\v4.0.30319\aspnet_isapi.dll
    64bit Framework: c:\windows\microsoft.net\framework64\v4.0.30319\aspnet_isapi.dll
    Make sure you uncheck the "Verify that file exists" checkbox
    Nuget-Returns-404-Explorer-IIS-Wildcard

Et voila your packages should all be working again.

Leave a comment if you need any additional help or it helped you.

 

Don't forget to follow me on Twitter.

# Friday, February 25, 2011

Recurring payment provider options for a UK start-up

Friday, February 25, 2011 3:42:23 PM (GMT Standard Time, UTC+00:00)
paymentgatewaylogos[1]

As many of you will know, we're currently in the process of launching a new online service -Crisis Cover which is a digital safe for your business' digital assets. A week before the launch we ran into a  slight hiccup in regards our payment gateway. The problem is simple:

The trouble with this: to trade for a year, we need some way of taking payments for the service; so we had to start looking into alternative payment gateways.

Our requirements

  • Low processing fees as the lowest plan is only £4.99
  • UK based payment gateway
  • Offer (or didn't require) a merchant account number
  • Billable in GBP
  • Handles the recurring element of the payments (so we didn't need to write a custom handler)
  • Trusted brand
  • Allows on-site payments (though this wasn't too much of a priority)

The payment gateways we looked into were:

Skip Our findings and jump to our conclusion.

Our findings

PayPal

For

  • Quick setup
  • Known and trusted brand
  • Wide market penetration
  • Simple integration
  • Fully managed service
  • No merchant account number required

Against

  • High monthly charge for a business account with montly recurring payments
  • Perceived as a B2C service rather than a B2B service
  • Constantly tries to upsell it's payment system to the customer (although the Website Payment Pro onsite option should work around that)
  • A large number of mix-and-match services it's hard to identify which one you need

Verdict

Although PayPal's offering is very appealing, it is still perceived very much as B2C service which is the main reason we decided against it. In addition to this, their monthly charge for the service we need and processing fees make it a potentially unviable solution to launch with.

For recurring payments, you will need Website Payments Pro with their monthly subscription upgrade which is currently an additional £20pcm (it's buried deep but you can learn more on this page -click the "Reporting & Back Office" tab).

Google Checkout

For

  • No setup charge or monthly fee
  • Quick setup
  • Known and trusted brand
  • Simple integration
  • No merchant account number required

Against

  • Offsite payment (thought they suggest you can do onsite too)
  • Recurring payments are in beta
  • General "feel" of the checkout experience is clunky
  • Not clear how to checkout if you don't have a Google Account

Verdict

Google's offering is certainly very appealing however the lack of non-beta subscription services meant that we didn't explore it further.

SagePay

For

  • No setup charge
  • Simple billing model
  • Known and trusted brand
  • Simple integration
  • No merchant account number required

Against

  • No recurring payment facility
  • Potentially slow setup

Verdict

SagePay's offering is a good solution that we have integrated with many times. Their API makes taking payments onsite quick and simple however there is currently no recurring payment system built in so we initially discounted them*.

* See conclusion

Zuora

For

  • Complete solution (apparently)

Against

  • Overly flashy website that doesn't tell you how much it costs
  • Appears to be predominantly US based

Verdict

Although it may seem petty, if you can't find out even the most basic information on the company website it makes me think that they're massively overpriced or not ready to take clients. So sadly, Zuora were ignored due to the lack of useful information.

Recurly

For

  • Handles recurring payments
  • Quick setup
  • Simple integration
  • Fully managed service
  • Invisible to the customer

Against

  • Not a payment gateway
  • Another additional monthly cost

Verdict

We've come across Recurly before and we initially discounted it as we didn't understand what it was/did. On revisiting their service in more detail however we realised what it does -and it's actually pretty good/helpful.

Recurly is not a payment gateway. Now I've got that out of the way, I should explain what it is. Recurly is a system that integrates with third party payment gateways e.g. SagePay and enables you to use these third party payment gateways to take recurring payments without requiring Continuous Authority with the acquiring bank.

This is massively important because Continuous Authority is usually what a start-up gets rejected on. Continuous Authority is basically a contract between the acquiring bank (the one "taking" the money) and the customer's bank which allows the acquiring bank to charge the customer (in theory) whenever -and however much- they like. This is obviously seen as a trust issue -especially when the company is a new entity with no trading history.

So Recurly opens up a whole new potential avenue of payment providers (within their group of partners of course!) which is when we took another look at SagePay.

AlertPay

For

  • No setup charge or monthly fee
  • Handles recurring payments
  • Active development community

Against

  • Appears to be a similar concept to PayPal (encourages the user to have an AlertPay account)
  • Lots of very small small print (check their prices page and "Some industries may be subject to a fee of 3.90 % + £0.59 GBP or equivalent for receiving funds from e-wallet and 6.40 % + £0.39 GBP for receiving funds by credit card")

Verdict

The offering from AlertPay looks good however because it encourages users to sign up for one of their accounts and they've not got enough market penetration yet to be a known/trusted brand which is a key factor in our decision.

CheddarGetter

For

  • Handles recurring payments
  • Quick setup
  • Simple integration
  • Fully managed service
  • Invisible to the customer

Against

  • Requires a Merchant Account
  • Very costly
  • Not a payment gateway

Verdict

CheddarGetter is very similar to Recurly, just more costly. It's also not clear if your Merchant Account requires Continuous Authority.

Spreedly

For

  • Handles recurring payments
  • Quick setup
  • Simple integration
  • Fully managed service
  • Invisible to the customer

Against

  • Not a payment gateway

Verdict

Spreedly is very similar to Recurly as well. We would need to compare them side by side sperately but although the website was clean and clear, the price reasonable (for 200 customers it would be $10pcm cheaper than Recurly). The lack of "pretty" information without signing up put us off. We read through the gumph however we were still left feeling it wasn't quite up to the same standard as Recurly.

Chargify

For

  • Handles recurring payments
  • Quick setup
  • Simple integration
  • Fully managed service
  • Invisible to the customer

Against

  • Monthly charge
  • Requires a merchant account

Verdict

We came across Chargify very early on and again is very similar to Recurly, they've recently changed their pricing structure which has made it completely unfeasible to even consider them.

Authorize.Net

For

  • Handles recurring payments
  • Quick setup
  • Simple integration
  • Fully managed service

Against

  • Primarily US based
  • $99.00 setup fee
  • Monthly fee of $30

Verdict

Authorize.Net offer the entire solution for what is a relatively low monthly fee however as they're mainly a US based company, this raises complications for us as a UK based company.

Xylyx

For

  • Quick setup
  • Simple integration
  • Low processing charges
  • No setup fee
  • Based in the UK

Against

  • Doesn't yet handle recurring payments
  • Backed by www.moneybookers.com so encourages the user to sign up for an acount

Verdict

We immediately signed up to Xylyx having spoken to Robert Atkin who overviewed their offering to us in some detail. It's a very good service all in all however the one thing that let it down for us was the fact that they don't yet have recurring billing built in (though it's due to launch this month).

If we were looking for a standard payment gateway (or when they've rolled out their repeat payments) we'd look at Xylyx again. Despite a somewhat bland website, Robert was very helpful.

The Conclusion

After carefully reviewing the options available to us, if you're looking to setup a service in the UK with recurring payments and minimal fuss I recommend the following order of options:

  • Recurly with SagePay
  • Spreadly with SagePay
  • Recurly with Authorise.Net
  • Spreadly with Authorise.Net
  • Recurly with PayPal Website Pro
  • PayPal Website Pro with recurring billing
 

Don't forget to follow me on Twitter.

# Wednesday, December 22, 2010

How to: Remove all users from the ASP.Net Membership database by application name

Wednesday, December 22, 2010 7:08:47 PM (GMT Standard Time, UTC+00:00)

delete_key[1]A while ago I wrote about How to: Remove users from the ASP.Net membership database which showed you how to remove a single user from the ASP.Net membership database from SQL Management Studio. That's great when you're deleting one or two users but what if you're testing and need to delete all users associated with an application?

There's a little more work involved with that one but it's not too difficult, rather than passing in the member's id, you pass in the ApplicationName (same as you set in your web.config) and it will find the various users that match and remove them for you.

USE DatabaseName --This should be your database name
GO

BEGIN TRANSACTION

DECLARE @ApplicationName nvarchar(256)
SET @ApplicationName = '##YOUR APPLICATION NAME -AS SET IN THE WEB.CONFIG ##'

--Lowercase it so it matches LoweredApplicationName exactly 
SET @ApplicationName = LOWER(@ApplicationName)

--Values in the aspnet_Profile table
DELETE p
FROM
	dbo.aspnet_Applications a 
		INNER JOIN dbo.aspnet_Users u ON a.ApplicationId = u.ApplicationId
		INNER JOIN dbo.aspnet_Profile p ON u.UserId = p.UserId
WHERE a.LoweredApplicationName = @ApplicationName

--Values in the aspnet_UsersInRoles table
DELETE r
FROM
	dbo.aspnet_Applications a 
		INNER JOIN dbo.aspnet_Users u ON a.ApplicationId = u.ApplicationId
		INNER JOIN dbo.aspnet_UsersInRoles r ON u.UserId = r.UserId
WHERE a.LoweredApplicationName = @ApplicationName

--Values in the aspnet_PersonalizationPerUser table
DELETE p
FROM
	dbo.aspnet_Applications a 
		INNER JOIN dbo.aspnet_Users u ON a.ApplicationId = u.ApplicationId
		INNER JOIN dbo.aspnet_PersonalizationPerUser p ON u.UserId = p.UserId
WHERE a.LoweredApplicationName = @ApplicationName

--Values in the aspnet_Membership table
DELETE m
FROM
	dbo.aspnet_Applications a 
		INNER JOIN dbo.aspnet_Users u ON a.ApplicationId = u.ApplicationId
		INNER JOIN dbo.aspnet_Membership m ON u.UserId = m.UserId
WHERE a.LoweredApplicationName = @ApplicationName

--Values in the aspnet_users table
DELETE u
FROM dbo.aspnet_Applications a INNER JOIN dbo.aspnet_Users u ON a.ApplicationId = u.ApplicationId
WHERE a.LoweredApplicationName = @ApplicationName

ROLLBACK TRANSACTION
 

Don't forget to follow me on Twitter.

# Monday, November 08, 2010

Download Umbraco content properties into a crosstab table

Monday, November 08, 2010 4:37:19 PM (GMT Standard Time, UTC+00:00)

Have you ever needed to get a download of your Umbraco content nodes in a cross-tab query e.g. download contact form data from Doc2Form? Using Umbraco's Contour product makes this a breeze but what about older systems? Thankfully, it's not actually that difficult.

We have a contact us form on one of our sites which uses an old version of Doc2Form which emails the customer details of the enquiry. One benefit is it also saves it to the recycle bin as a document with the name: "RE: SYSTEM DATA: umbraco master root". With that in mind, we can use SQL Server's PIVOT functionality to pull the data out in a nicely formatted manner.

Firstly you'll need to know the id's of the document type's properties, there are numerous ways to do this:

1. Just look at the cmsPropertyData table for a couple of content nodes (I could spot the ones I was after fairly easily)

 

2. Query the cmsPropertyType table:

Find the contentTypeId of the document type -you can do this by hovering your mouse over the document type in the tree and checking out the status bar (you can see the contentTypeId in brackets in the bottom left -mine here is 1074):

image

Once you have the contentTypeId of the document type, you can then get the ids of all the properties you're after by replacing "xxx" with your property id in the following script:

SELECT * FROM dbo.cmsPropertyType WHERE contentTypeId = xxx

3. Get it from the source of the document type editor

An alternative way is to examine the HTML of the Document Type editor. If you view the source on the "Generic Properties" tab and scroll to the section you're interested in (there'll be a h2 with the same name) you will find a ul that has the class of "genericPropertyList".

Each li of that ul will have the relevant id as part of it's id e.g. for a section called "Enquiry Form" the id will be: "EnquiryFormContents_49" where "49" is the id we're interested in. You can see mine (49, 50, 51 and 52 below):

image

Once you have these ids to hand (mine were 49, 50, 51 and 52) you just need to update the code below and run against your Umbraco database:

SELECT
	contentNodeId As [Id], 
	[49] As [Name], 
	[50] As [Telephone], 
	[51] As [Email Address], 
	[52] As [Notes]
FROM
(
	SELECT contentNodeId, propertytypeid, ISNULL(dataNvarchar, dataNtext) As [Value]
	FROM dbo.cmsPropertyData
) As src
PIVOT (
	MAX(Value) 
	FOR propertytypeid in ([49], [50], [51], [52])
) aS pvt
WHERE [50] IS NOT NULL OR [51] IS NOT NULL
ORDER BY contentNodeId

 

That will then produce some lovely formatted data for you, my example above produced:

Id Name Telephone Email Address Notes
1154 Example 01234567890 test@test.com Please contact me as soon as possible about your great site, thanks.

 

It's also possible to automate this entire script so you don't need to find out the property ids, I'll post that separately.

 

Don't forget to follow me on Twitter.

# Monday, October 04, 2010

Delete all UCommerce baskets older than x days

Monday, October 04, 2010 10:14:31 AM (GMT Daylight Time, UTC+01:00)

After my last UCommerce post on how to delete test orders and baskets from UCommerce, Søren suggested I extended the delete all baskets code to take into account when it was created. As my last code was relating to deleting test orders/baskets (and so would want to get rid of them all), I decided to post this one separately.

Delete all baskets older than x days

To use this, all you need to do is change the @addedBefore parameter to whatever date/time you want (or just adjust the –7 which represents seven days in the past.

--Delete all carts purchaseorders and associated data within x days
DECLARE @addedBefore smalldatetime
--By default the script deletes everything older than 7 days
SET @addedBefore = DATEADD(dd, -7, GETDATE())

BEGIN TRAN

UPDATE uCommerce_PurchaseOrder SET BillingAddressId = NULL WHERE OrderNumber IS NULL AND CreatedDate <= @addedBefore
DELETE a FROM uCommerce_Shipment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE a FROM uCommerce_OrderAddress a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE a FROM uCommerce_OrderProperty a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE a FROM uCommerce_OrderLine a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE a FROM uCommerce_Payment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE a FROM uCommerce_OrderStatusAudit a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL AND b.CreatedDate <= @addedBefore
DELETE FROM uCommerce_PurchaseOrder WHERE OrderNumber IS NULL AND CreatedDate <= @addedBefore

--Uncomment this
--COMMIT TRAN

--And comment out this
ROLLBACK TRAN
 

Don't forget to follow me on Twitter.

# Friday, October 01, 2010

Deleting test orders and baskets from uCommerce

Friday, October 01, 2010 12:53:43 PM (GMT Daylight Time, UTC+01:00)

Although Søren has posted a helpful post on how to delete entire purchase orders from the database here, we needed something a little less “all or nothing” so put the below together.

Delete a specific order id

--Delete purchaseorders and associated data based on order id
DECLARE @OrderNumber nvarchar(50)
SET @OrderNumber = 'TEST-40'

BEGIN TRAN

UPDATE a SET ShipmentId = NULL FROM uCommerce_OrderLine a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE OrderNumber IS NULL
UPDATE uCommerce_PurchaseOrder SET BillingAddressId = NULL WHERE OrderNumber = @OrderNumber
DELETE a FROM uCommerce_Shipment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE a FROM uCommerce_OrderAddress a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE a FROM uCommerce_OrderProperty a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE a FROM uCommerce_OrderLine a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE a FROM uCommerce_Payment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE a FROM uCommerce_OrderStatusAudit a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
DELETE FROM uCommerce_PurchaseOrder WHERE OrderNumber = @OrderNumber

--TODO: Expand this so it checks for other orders
--DELETE a FROM uCommerce_Address a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber
--DELETE a FROM uCommerce_Customer a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber = @OrderNumber

--Uncomment this
--COMMIT TRAN

--And comment out this
ROLLBACK TRAN

 

 

Delete all baskets

--Delete all carts purchaseorders and associated data

BEGIN TRAN

UPDATE a SET ShipmentId = NULL FROM uCommerce_OrderLine a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE OrderNumber IS NULL
UPDATE uCommerce_PurchaseOrder SET BillingAddressId = NULL WHERE OrderNumber IS NULL
DELETE a FROM uCommerce_Shipment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE a FROM uCommerce_OrderAddress a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE a FROM uCommerce_OrderProperty a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE a FROM uCommerce_OrderLine a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE a FROM uCommerce_Payment a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE a FROM uCommerce_OrderStatusAudit a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.OrderNumber IS NULL
DELETE FROM uCommerce_PurchaseOrder WHERE OrderNumber IS NULL

--TODO: Expand this so it checks for other orders
--DELETE a FROM uCommerce_Address a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.NULL = @NULL
--DELETE a FROM uCommerce_Customer a INNER JOIN uCommerce_PurchaseOrder b ON a.OrderId = b.OrderId WHERE b.NULL = @NULL


--Uncomment this
--COMMIT TRAN

--And comment out this
ROLLBACK TRAN

 

Update: At the request of Søren, I’ve altered the delete all baskets post so it allows you to delete all baskets older than a given date, see: Delete all UCommerce baskets older than x days

 

Don't forget to follow me on Twitter.

# Wednesday, August 18, 2010

Developer Pitfall: When to call it quits on a problem

Wednesday, August 18, 2010 4:50:07 PM (GMT Daylight Time, UTC+01:00)

frustration[1]We’ve all done it, you’ve run into a problem while developing which you bash at for a few hours and before you know it, you’ve lost the day, not got anywhere and feel completely frustrated. What’s more, is it’s usually something so screamingly obvious and/or simple that you just know you’ll find the answer on Google.

Rather than pulling your hair out for hours on end, there’s a rather simple rule-of-thumb that you should follow:

If you’re able to bash at it for 30 minutes without feeling you’re getting any closer, you’re probably looking at it from the wrong direction and having someone else’s perspective on the problem will probably answer it within seconds. By walking away from the problem you’re also taking away the pressure and you’ll often find the solution comes to you.

Another advantage of putting a time limit on the issue is it avoids you losing the day and should also mean you’ve explored Google and the lists so when you ask your “friend”, it should stop you getting that annoying lmgtfy response when asking for help (it’s a similar concept to the “wait 1 minute before sending” facility within Outlook).

So the next time you realise something’s taking longer than you think it should, start the timer!

 

Don't forget to follow me on Twitter.

# Wednesday, April 21, 2010

Stop jQuery.hide() showing the elements on page load

Wednesday, April 21, 2010 10:30:25 PM (GMT Daylight Time, UTC+01:00)

This is a great little tip that Andy Higgs shared with me a couple of months ago while we were developing Crisis Cover. If you write jQuery that hides the div when the user has JavaScript enabled, you can avoid the divs all being shown while the page loads by simply adding a class to the body of the page using jQuery and hide it using CSS like so:

<html>
<head></head>
<!-- Reference to jQuery here -->
<body>
<!-- This should be the first bit of code and don't wait until the page has loaded -->
<script type="text/javascript">$('body').addClass('js');</script>
<!-- The rest of your code here -->
<div class="jsHide">
	<p>This paragraph is hidden if the user has JavaScript enabled.</p>
</div>
</body>
</html>

 

Then you just need to add the css:

.js .jsHide

Your divs will now be hidden until you show them with JavaScript. Nice, simple solution to an ever annoying problem.

Note: For my demo to work you'll need to include jQuery

Update: As pointed out by Petr below and Andy Higgs/Trevor Morris, it would be better to target using JavaScript without jQuery and target the body for maximum flexibility (note the space at the front in case there is already a class):

<script type="text/javascript">document.getElementsByTagName('html')[0].className+=' js'</script>
 

Don't forget to follow me on Twitter.

# Saturday, February 27, 2010

Collapse all Solution Explorer items in Visual Studio 2010

Saturday, February 27, 2010 12:22:48 PM (GMT Standard Time, UTC+00:00)

Ever wanted to be able to collapse all items within Visual Studio's solution window? This is a nifty little Visual Studio macro that I came across a few years ago and have been using successfully in Visual Studio 2005, Visual Studio 2008 and now in the Visual Studio 2010 RC.

I'll overview how to install it below in case you're unsure how to do it but I have this bound to the key combination Ctrl+Shift+` as ReSharper now uses my previous key combination of Ctrl+` for it's new bookmark explorer.

Anyway, here's the Visual Studio Solution Explorer item Collapse All macro:

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
'-----------------------------------------------------------
' CollapseAll Module
'-----------------------------------------------------------
' Simple macro that fully collapses all items in the 
' Solution Explorer rather than just the top level node
'
' To make live easier, bind it to a keyboard setting such
' as Ctrl+Shift+` which by default has no bindings (Ctrl+` is
' now used by Resharper
'
' Tested and works with:
' Visual Studio 2005
' Visual Studio 2008
' Visual Studio 2010
'
' Originally from: http://bit.ly/bmRu3W
'-----------------------------------------------------------
Public Module CollapseAll

    Sub CollapseTree()
        ' Get the the Solution Explorer tree
        Dim solutionExplorer As UIHierarchy
        solutionExplorer = DTE.Windows.Item(Constants.vsext_wk_SProjectWindow).Object()

        ' Check if there is any open solution
        If (solutionExplorer.UIHierarchyItems.Count = 0) Then
            Return
        End If

        ' Get the top node (the name of the solution)
        Dim rootNode As UIHierarchyItem = solutionExplorer.UIHierarchyItems.Item(1)
        rootNode.DTE.SuppressUI = True

        ' Collapse each project node
        Collapse(rootNode, solutionExplorer)

        ' Select the solution node, or else when you click 
        ' on the solution window
        ' scrollbar, it will synchronize the open document 
        ' with the tree and pop
        ' out the corresponding node which is probably not what you want.
        rootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
        rootNode.DTE.SuppressUI = False
    End Sub

    Private Sub Collapse(ByVal item As UIHierarchyItem, ByRef solutionExplorer As UIHierarchy)
        For Each innerItem As UIHierarchyItem In item.UIHierarchyItems
            If innerItem.UIHierarchyItems.Count > 0 Then
                ' Re-cursive call
                Collapse(innerItem, solutionExplorer)
                ' Collapse
                If innerItem.UIHierarchyItems.Expanded Then
                    innerItem.UIHierarchyItems.Expanded = False
                    If innerItem.UIHierarchyItems.Expanded = True Then
                        ' Bug in VS 2005
                        innerItem.Select(vsUISelectionType.vsUISelectionTypeSelect)
                        solutionExplorer.DoDefaultAction()
                    End If
                End If

            End If
        Next
    End Sub
End Module

 

In case you've never installed a Visual Studio macro before, here's a couple of instructions:

  1. In Visual Studio, press Alt+F11 to load up the Visual Studio Macro editor (or View > Other Windows > Macro Explorer > Double Click on "Module1" in "My Macros")
  2. Either create a new module of it it's not in use, you can edit Module1 and past in the code above
  3. Save and close the Visual Studio Macro editor
  4. You should be back in Visual Studio so click "Tools > Options > Environment > Keyboard"
  5. In the "Show commands containing" text box, enter "CollapseTree" and the macro you just created should be shown.
  6. Make sure "Global" is selected in the "Use new shortcut in:" drop down list
  7. Press Ctrl+Shift+` in the "Press shortcut keys:" text box
  8. Click Assign
  9. Click OK

You're done :)

Update via Graeme: Make sure your module name (in the above it's Module1) is the same as your file name otherwise Step 5 minght not work.

 

Don't forget to follow me on Twitter.

# Tuesday, May 12, 2009

C# FileInfo.MoveTo Cannot create a file when that file already exists exception

Tuesday, May 12, 2009 8:39:35 PM (GMT Daylight Time, UTC+01:00)

This was one of those irritating errors that you get when you're trying to do something quickly before you go home and you can't for the life of you fathom the issue.

I had the following code (simple enough):

FileInfo f = new FileInfo("## File's Path ");
try
{
    f.MoveTo("## DROP OFF DIRECTORY ##"));
}
catch (Exception e)
{
    //Log the exception here
}

The fix was simple, you just have to remember to specify the new filename too. (DOH!). Here's the "correct" code.

FileInfo f = new FileInfo("## File's Path ");
try
{
    f.MoveTo(Path.Combine("## DROP OFF DIRECTORY ##", f.Name));
}
catch (Exception e)
{
    //Log the exception here
}

Hope that helps you out ;)

 

Don't forget to follow me on Twitter.

# Friday, April 17, 2009

Quick ASP.Net tip: Half your page size in ASP.Net instantly

Friday, April 17, 2009 3:53:05 PM (GMT Daylight Time, UTC+01:00)

Ok it might be a little less than half side but it's near enough. I've been sitting on this for a while and needed to reference it for someone so I thought I'd post quickly about it. One of the most common complaints about .Net is that you have a lot of hidden "content" by the way of hidden inputs and the likes throughout your site. This can easily get corrupt on postback/slowdown the page load times etc.

Really you should be optimising each control on the page (enabling/disabling where relevant) but if you want to cheat (lets face it, we all do):

  1. Download the files: PageStateAdapterv1.0.zip (3KB)
  2. Put PageStateAdapter.browser into your /App_Browsers/ folder (or create one and add it)
  3. Put TSDPageStateAdapter.dll into your website's /bin/ folder
  4. Load up your website and checkout your ViewState :)

Incase you're interested in the source for it:

PageStateAdapter.browser

<browsers>
    <browser refID="Default">
        <controlAdapters>
            <adapter controlType="System.Web.UI.Page" adapterType="TheSiteDoctor.PageStateAdapter.PageStateAdapter" />
        </controlAdapters>
        <capabilities>
            <capability name="requiresControlStateInSession" value="true" />
        </capabilities>
    </browser>
</browsers>

PageStateAdapter.cs

using System.Web.UI;

namespace TheSiteDoctor.PageStateAdapter
{
    public class PageStateAdapter : System.Web.UI.Adapters.PageAdapter
    {
        public override PageStatePersister GetStatePersister()
        {
            return new SessionPageStatePersister(this.Page);
        }
    }
}

The best example of how much this reduces ViewState by is when you add a large DataGrid to your site.

Post files: PageStateAdapterv1.0.zip (3KB)

Update: Apologies to those of you who downloaded and found it wouldn't compile, the .browser file was a little off (missing the second "PageStateAdapter"). I've updated it and changed the zip file download. Enjoy!

 

Don't forget to follow me on Twitter.

# Wednesday, November 26, 2008

IE classes DDD feedback site as a phishing site…

Wednesday, November 26, 2008 1:00:05 PM (GMT Standard Time, UTC+00:00)

This one made me laugh today, Chris Anderson alerted me to it but you would have thought the MS guys would have picked up on it...

2008-11-26_1151.png

Incidentally, it's the first time I've seen this message on any site...

2008-11-26_1152.png

 

Don't forget to follow me on Twitter.

# Wednesday, September 03, 2008

Clean out unused media items from Umbraco media folder

Wednesday, September 03, 2008 5:15:14 PM (GMT Daylight Time, UTC+01:00)

When uploading some new media items for a client today we noticed that if you selected "Remove" before saving, it doesn't actually remove the file from the FileSystem. Having a quick look around the forums I saw there are a few posts already pointing this out so I thought I'd fix it.

This is a little application that simply checks the media items in the database and then compares it against a folder you select on your machine. If the file is in use according to the database then it's ignored otherwise it will remove it.

To use:

  1. Enter your server's login details
  2. Click "Test Connection"
  3. Select the relevant database from the drop down
  4. Check the "Media Folder Name" matches your Umbraco's installation
  5. Locate your Media Folder on your computer
  6. Click "Check Media Folder" -this will then list all the orphan files
  7. If it looks right, click "Delete" -with caution
  8. Job done

There are a few checks in place to avoid mishap but it's not 100% foolproof as I needed something rough and ready to sort a couple of installations out. If this is something that's seen as useful I'll extend it a touch, some ideas I've got already:

  • Check that the selected media folder matches that of the database
  • Check that the media id's are the same (to avoid wiping another installation)
  • Save config settings for easy re-use
  • Use webservices rather than a direct connection to the database
  • Enable FTP useage

Please note: I accept no responsibility if anything was to go horribly wrong with this. I would backup your folder first just in case!

You can download the MediaFolderCleaner application here

 

Don't forget to follow me on Twitter.

# Tuesday, July 15, 2008

How to: Convert Hexadecimal Strings

Tuesday, July 15, 2008 10:25:56 AM (GMT Daylight Time, UTC+01:00)

As it's my Birthday today I thought I'd post a silly ditty. I'm currently altering Protx's old ASP.Net library to accommodate their changes in regards 3D Secure and while reflecting some of the code came across an enum with their number representations as Hexadecimal strings. I needed to convert these to decimals so thought I'd share a quick and easy way to do it.

Open up Window's Calculator (Windows Key + R then type in calc) under the View menu select "Scientific". Press the F5 key to switch over to Hex entry. Type in the value after the 0x and hit F6

Simple, easy and will help you convert all those Hexadecimal strings (ones that look like this: 0x01 or 0x1a).

Right, time for a coffee :)

 

Don't forget to follow me on Twitter.

How to: Convert Hexadecimal Strings
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [2]  Trackback LinkTrackback
CategoriesTags: C# | Development
# Saturday, June 21, 2008

UK Umbraco meet up

Saturday, June 21, 2008 12:17:58 AM (GMT Daylight Time, UTC+01:00)

In a previous post about CodeGarden 08, I asked people to get in touch if they'd be interested in a UK Umbraco meet up. I've had a fair few people get in touch so I think it's something worthwhile pursuing further. The nest stage from my POV is working out the location and potential content of the meet so I thought I'd open it up to the floor.

With the forthcoming DDD7, I thought it might be a ready-built platform that we could use but I agree with Phil that DDD7 may not be a suitable platform for a multitude of reasons.

As I've had people from the South West and Scotland voice an interest, I don't think it'll suit the majority of people to have it based in London so suggest it is based in the Midlands -probably Birmingham as it's easy to get to (M6 from the North, M4 from London, M5 from the South -or train!) and there are plenty of places to have the meet.

In regards the format/content of the meet, does anyone have any suggestions? We could follow Niels' and Per's open format or we can have a more structured theme? I've not had too much of a think as to subject matter but some I have come up with so far:

  • An introduction to Umbraco and what it is (many of the people I've spoken to have only just started using Umbraco)
  • Examples of Umbraco how Umbraco can be used
  • More advanced Umbraco functionality (membership etc)
  • Getting to grips with XSLT
  • How to sell Umbraco to your clients

So that's where I've got to so far, does anyone have anything to add?

BTW the logo is just a working logo atm, need to have Niels approve it ;)

Update: I have posted a post on the Umbraco forums about a UK Umbraco meet here

 

Don't forget to follow me on Twitter.

UK Umbraco meet up
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [4]  Trackback LinkTrackback
CategoriesTags: Development | The Site Doctor | Umbraco | Web Development
# Wednesday, June 18, 2008

Talk about a confusing error message

Wednesday, June 18, 2008 11:37:58 PM (GMT Daylight Time, UTC+01:00)

I don't mind when I get told I've made a mistake -or there's a problem with the system but this error message kinda takes the P! Quite what the developers were thinking when they wrote this one I'm not sure!

What do I do? celebrate that it went through ok or commiserate because it failed?

The "Ok." relates to the transaction completing without an issue, the "Stop" actually says that it failed so it's not even "Part A was ok, but Part B failed". Really odd, someone needs to look into testing their system.

Looks pretty though!

 

Don't forget to follow me on Twitter.

Talk about a confusing error message
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [2]  Trackback LinkTrackback
CategoriesTags: Design | Development | Random | Testing
# Tuesday, June 10, 2008

CodeGarden 08 -been there, done that, got the t-shirt!

Tuesday, June 10, 2008 7:18:53 PM (GMT Daylight Time, UTC+01:00)

So things have been manic here the past week, for those of you who didn't know, I popped over to Denmark at the last minute to attend Umbraco's CodeGarden 08. It was great fun and I have to thank Niels Hartvig and Per Ploug Hansen for putting on a great couple of days.

You can check out my photos from the event on Flickr (bear with me, I'm just getting started with Flickr).

I'm sure a fair few people have blogged about the highlights (if you're interested check www.umbraco.org) but the biggy was announcing the release of Umbraco v3.14.0 which is pretty exciting news as it has a ton of feature enhancements and UI improvements. Also, you'll be pleased to hear that they're making 2008 the year of Umbraco documentation!

Another interesting points from the conference was the pending release of Umbraco.TV which will feature tutorial videos and insights from the core team on how to use Umbraco and the Umbraco store which allows you to easily distribute the packages you make :) All in all some interesting developments.

There were also a fair few English developers at the conference so discussion inevitably turned to a UK meet (I know there are a fair few designers and developers here that couldn't justify the expense) so that's something that I'm going to look into setting up. If this is something you'd be interested in, leave a comment or drop me an email and we'll see how much interest there is.

To all the rest of you -it was great to meet you, you're all a lovely bunch and I look forward to meeting you again at CodeGarden 09!

The other thing I've finally clarified (this is for you Simon!) is the Umbraco licensing rules so if you're unsure on those, check out my post on when you need to purchase an Umbraco license (the answer is always -or never, it's up to you!).

 

Don't forget to follow me on Twitter.

# Monday, June 09, 2008

When do I need to buy an Umbraco license?

Monday, June 09, 2008 6:16:00 PM (GMT Daylight Time, UTC+01:00)

This may seem a slightly obvious/silly post but the answer is simple -it's just not *that* well documented/explained.

In a nutshell there are three scenarios you need to worry about:

  • Using Umbraco in a non-commercial environment with the branding (logos etc) intact -no fee
  • Using Umbraco in a commercial environment with the branding (logos etc) intact -no fee
  • Using Umbraco in a commercial environment without the branding (logos etc) -fee

So there you have it. But to be fair, you should always pay for it if you're using it in a commercial environment just because it's a great product (and it's good for your karma!)

 

Don't forget to follow me on Twitter.

# Thursday, May 29, 2008

A seriously elegant SQL Injection -how it was sorted

Thursday, May 29, 2008 3:32:33 PM (GMT Daylight Time, UTC+01:00)

Doug Setzer posted this comment in response to my recent "A seriously elegant SQL Injection" post and I thought it may be of interest to others so have promoted it to a post...


Well, I'll step up and say that I am the "mate" who had this done.  Tim's right - *always* sanitize your inputs.  In my defence, this was a site that I inherited from a previous contractor.  I'm not entirely absent of blame, I still should have done a security sweep through the code.

I'd like to document the steps that I went through once this was identified to try and avoid this kind of thing in the future.

  1. Edit every web page that executes a query to sanitize any parameters that are passed in.  Since the site was classic ASP, I used my "SQLStringFieldValue" function:
    www.27seconds.com/kb/article_view.aspx?id=50
  2. Modify the DB user account that is used to have *read only* access to the database
  3. Modify the pages that DO write to the database to have *read/write* access to the specific tables that are being changed.  This limits the number of places that SQL Injection can occur to a smaller set than was previously possible.  I still sanitize all of my input, but I'm extra spastic in these database calls.
  4. Add database auditing (triggers writing to mirror tables with audit event indicator & date/time) to see when data changes occur.  This is still problematic with the pages that have "write" permissions to the tables, but again- that footprint is much smaller.
    My future plans are to move to a view/stored procedure based architecture.  I can then limit write permissions to just the stored procedures and read permissions to just the views.  My grand gusto plans are to move to using command objects & parameters, but I'd sooner re-write the entire site.

Although Doug's attack wasn't the same nihaorr1.com attack that's going around atm it was similar so I would imagine other's will find this useful.

It still amazes me how many developers still fail to sanitise strings, only last week I came across another site (in PHP) that was allowing simple SQL injections to be used to log into their administration system. It was down to a problem with the sanitization string, but why not at least check your site before it goes live? It takes 2 minutes and even less to fix...

For those of you who need a few pointers, there's a good discussion or two about sanitising strings on the 4 Guys From Rolla site.

 

Don't forget to follow me on Twitter.