Is this safe against major XSS attacks?
Is it safe?  Maybe.  Is it the right way to do it?  No.

Even if it were safe, there’s a big problem with the SQL, and that’s that you’re inserting the dots after escaping, rather than before.  I notice that for the input ', it will be escaped to \', and then your dot-insertion turns it into \.'..  Before, the \ was escaping the ', but now it isn’t.  Now it’s escaping the ..  I don’t know if a malicious entity could do anything bad with that, but I wouldn’t take any chances.

And here are some problems with the HTML:


Copy-and-pasting will catch those dots.
Search engines will catch those dots.
You break any Unicode characters, e.g. you turn 日本語 into ?.?.?.?.?.?.?.?.?.. (But I only have an old version of PHP installed; maybe newer versions are more intelligent, but in that case, you might have other problems like putting a combining character onto your &gt;)


And that’s not to mention the gigantic size increase, and potentially having invalid HTML… all around, it’s just not a very good way to do it.

So what’s the right way to do it?  Well, for inserting data into the database, you should be using PDO with prepared statements.  Then you don’t have to deal with SQL escaping at all: you prepare a query with placeholders, and send in the placeholder data, and since the data doesn’t have to touch the query, you don’t have to worry about that at all.

Sidebar: using PDO

You said that it’d be a lot of work to use PDO.  Well, I’ve never found it particularly difficult.  Your code perhaps looks like this:

mysql_connect('localhost', 'myapp', 'letmein');
mysql_select_db('myapp');
// ...
mysql_query("insert into users (firstname, lastname, email) values ('$firstname', '$lastname', '$email')");


But it’s not actually that hard to use PDO.  That code could be translated to use prepared statements and PDO like so:

$db = new PDO('mysql:host=localhost;dbname=myapp', 'myapp', 'letmein');
// ...
$stmt = $db-&gt;prepare('insert into users (firstname, lastname, email) values (:firstname, :lastname, :email)');
$stmt-&gt;bindValue('firstname', $_POST['firstname']);  // look ma, no escaping!
$stmt-&gt;bindValue('lastname', $_POST['lastname']);
$stmt-&gt;bindValue('email', $_POST['email']);
$stmt-&gt;execute();


And besides being more secure, you’re also moving onto something that the PHP developers have committed to keep in place: the mysql_* functions will be removed, as the PHP documentation says:


  Warning: This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information.


End of sidebar

On the HTML side, using htmlentities or htmlspecialchars is the standard way to do it.

Then, finally, I’d like to point out one thing about how you’re accessing POST data: you’re currently using $_POST[firstname].  It’s supposed to be an expression that’s between the brackets, but you have the name of the field literally in there.  It turns out that that’s okay currently, as undefined constants evaluate to their name.  But that does generate a notice, and depending on your error reporting level, you will probably see lots of notices in your error log saying that this is bad and/or deprecated.  You should explicitly quote it: $_POST['firstname'].