The answer here is to use prepared statements with placeholder values in an extremely disciplined manner. Any and all user data, be it directly from form inputs, query parameters, session data, or other database records, must be treated as possibly hostile and, as such, needs escaping. The most reliable way to escape that when dealing with the database is to use placeholder values, maintaining strict separation between query and data.
For example:
INSERT INTO users (name, shoes) VALUES (?, ?)
Where those ?
values represent arbitrary user data. With bind_param
you can bind against these:
$stmt->bind_param('si', $_POST['name'], $_POST['shoes']);
Where that properly encodes that as a string and integer, respectively.
When displaying content you'll need to be aware that it's also important to escape that for the context you're rendering it in, be that HTML, JavaScript/JSON, or a URI, each of which have different requirements and formats.
Always store your data in the most neutral format. Never pre-escape HTML or strip characters arbitrarily. Non-destructive cleaning, such as trimming leading and trailing spaces, is fine, but any aggressive formatting not related to normalization to an ideal form should be discouraged.