WORDS
Escape-tecken: PHP
PHP är ett språk med många olika behov av escapning. Här går vi igenom några exempel.
Strängar
I PHP finns fyra olika av strängsyntaxer, som escapas på olika sätt: apostrof, citattecken, heredoc och nowdoc. Här beskrivs syntaxen mycket kort. Mer information hittas i PHP:s dokumentation.
Fnuttar
I strängar som omges med apostrofer escapar man bara '
och \
, och den senare är faktiskt inte alltid nödvändig.
<?php
// Ger: He said: "Please don't"
echo 'He said: "Please don\'t"';
// Ger: Filen finns på C:\
echo 'Filen finns på C:\\';
// Ger: domain\user
echo 'domain\user';
// Ger: domain\user
echo 'domain\\user';
?>
PHP har också stöd för interpolerade strängar med citattecken. I dessa strängar kan man escapa många fler tecken, exempelvis radbrytning med \n
.
<?php
$name = "världen";
// Ger: Hej världen!
echo "Hej $name!";
// Ger: Hej $name!
echo "Hej \$name!";
// Ger:
// Han sa: "Låt bli"
// Hon sa: "Jag gör som jag vill"
echo "Han sa: \"Låt bli\"\nHon sa: \"Jag gör som jag vill\"";
?>
Nowdoc och heredoc
Om man är trött på escapning, så kan man använda nowdoc-syntaxen. I exemplet nedan har vi valt att inleda den med EOT
, men man kan välja vad som helst som inte kommer ingå i strängen. Strängen avslutas med den valda texten på en egen rad - utan indentering.
<?php
function print_message() {
// Ger:
// Han sa: "Låt bli"
// Hon sa: "Jag gör som jag vill"
// Bakvänt snedstreck escapas inte: \\ \'
echo <<<'EOT'
Han sa: "Låt bli"
Hon sa: "Jag gör som jag vill"
Bakvänt snedstreck escapas inte: \\ \'
EOT;
}
?>
Om man vill ha tillgång till interpolering och escapning - som i strängar omgivna av citattecken "
- så kan man använda den närliggande syntaxen heredoc.
<?php
function print_message() {
$ett = 'Han';
$två = 'Hon';
// Ger:
// Han sa: "Låt bli"
// Hon sa: "Jag gör som jag vill"
// Escapning fungerar: \
echo <<<EOT
$ett sa: "Låt bli"
$två sa: "Jag gör som jag vill"
Escapning fungerar: \\
EOT;
}
?>
Regex
PHP har inga regex-literals. Istället skickar man in strängar till funktioner som använder regex. Detta ger liknande problem som RegExp
-syntaxen i Javascript.
SQL
Man använder ofta PHP tillsammans med databaser. I MariaDB/MySQL escapas strängar med \
.
<?php
$surname = "O'Reilly";
$mysqli = new mysqli("localhost", "my_user", "my_password", "db");
// DÅLIGT
// Syntaxfel: Den resulterande frågan innehåller en omatchad apostrof.
// SELECT * FROM users WHERE surname = 'O'Reilly';
$mysqli->query("SELECT * FROM users WHERE surname = '$surname';");
// BÄTTRE
// Man bör använda den inbyggda escape-funktionen.
$surname_escaped = $mysqli->real_escape_string($surname)
// SELECT * FROM users WHERE surname = 'O\'Reilly';
$mysqli->query("SELECT * FROM users WHERE surname = '$surname_escaped';");
$mysqli->close();
?>
Om man glömmer att escapa inparametrar till en SQL-fråga, så utsätter man sig för SQL-injektioner. Det går ut på att angripare, genom att konstruera en viss input, kan köra sin egen SQL-fråga i databasen. Se mer information i min artikel om säkerhet för webbplatser.
Magic quotes
I tidigare versioner av PHP fanns inställningen magic quotes. Funktionen escapade automatiskt användarinput, utifall att den skulle användas i en databasfråga. Det gällde $_GET
, $_POST
, $_COOKIE
och $_REQUEST
, som fylls på automatiskt från användarens request.
Problemet var ju bara att det inte var alldeles säkert att man behövde escapa för databasfrågor. Ibland skickar man kanske ett mejl. Eller skickar ut den som del av HTML:en. Då behövs inga extra \
. Detta ledde till onödigt krånglig kod...
<?php
// Användaren har skickat in: O'Reilly
echo $_POST['name']; // O\'Reilly
if (get_magic_quotes_gpc()) {
// Omvända snedstreck har lagts till automatiskt.
// Ta bort dom!
$name = stripslashes($_POST['name']);
} else {
$name = $_POST['name'];
}
echo "Hej $name"; // Hej O'Reilly
// Om det ska användas med MySQL kan man
// lägga tillbaka dom på ett säkert sätt.
$name_escaped = $mysqli->real_escape_string($name);
$sql = "INSERT INTO names VALUES ('$name_escaped')";
?>
Tack och lov togs denna inställning bort helt i PHP 5.4, som släpptes år 2012.
Vidare information, och alla anledningar till att detta var en hemsk ide, hittas på Wikipedia.