On another note (unsolicited, so take it for what it's worth), you have a persistent (or stored) XSS security issue here. This is where XSS might be stored in the database (got there because of some other vulnerability allowing it to be entered in the first place) and subsequently written out to the browser with no sanitization. Best practice is to sanitize data coming in AND going out.
https://www.owasp.org/index.php/Cross-siteScripting(XSS))
If you add a simple piece of code, perhaps in a class with a static function, to sanitize your input, you could change:
echo '<td>'. $row['surname'] . '</td>';
to something like:
echo '<td>'. Security::Sanitize($row['surname']) . '</td>';
You'd have to write the function yourself, or find a decent library. It's a pain, I know, to do this every place you're sending data out, but in the end, it's well worth the effort.
Imagine if the surname field contained a bit of javascript from a malicious entry. For example, just a simple:
<script>alert('xss');</script>
Without sanitizing, when sending the output to the browser, that javascript would actually be executed. Not good. Sanitizing this would possibly change this to just:
<script>alert('xss');</script>
Harmless at that point.
Sanitizing could be as simple as a function like this, though a decent security library would be better. At least this is better than nothing.
class Security
{
public static function Sanitize($text)
{
$text = mb_detect_encoding($text, mb_detect_order(), true) === "UTF-8" ? $text : mb_convert_encoding($text, "UTF-8");
$html = htmlspecialchars($text, ENT_NOQUOTES | ENT_SUBSTITUTE, "UTF-8");
return $html;
}
}
Anyway, thought I'd mention it, if it's of any value to you.