こんにちは!今回は、PHPの標準関数であるstripslashes()について詳しく解説していきます。addslashes()でエスケープされた文字列を元に戻すための関数です!
stripslashes関数とは?
stripslashes()関数は、addslashes()によって追加されたバックスラッシュを削除する関数です。
シングルクォート(')、ダブルクォート(")、バックスラッシュ(\)、NULL文字(\0)の前に付けられたバックスラッシュを取り除きます!
基本的な構文
stripslashes(string $string): string
- $string: バックスラッシュを削除する文字列
- 戻り値: バックスラッシュが削除された文字列
基本的な使用例
シンプルな使用例
// addslashes()でエスケープ
$original = "It's a beautiful day";
$escaped = addslashes($original);
echo "エスケープ後: " . $escaped . "\n";
// 出力: It\'s a beautiful day
// stripslashes()で元に戻す
$restored = stripslashes($escaped);
echo "復元後: " . $restored . "\n";
// 出力: It's a beautiful day
// 完全に一致するか確認
var_dump($original === $restored); // bool(true)
各種クォートの処理
// シングルクォート
$text = "She said, 'Hello'";
$escaped = addslashes($text);
echo $escaped . "\n"; // She said, \'Hello\'
echo stripslashes($escaped) . "\n"; // She said, 'Hello'
// ダブルクォート
$text = 'He said, "Hi"';
$escaped = addslashes($text);
echo $escaped . "\n"; // He said, \"Hi\"
echo stripslashes($escaped) . "\n"; // He said, "Hi"
// バックスラッシュ
$text = "Path: C:\\Users\\Documents";
$escaped = addslashes($text);
echo $escaped . "\n"; // Path: C:\\\\Users\\\\Documents
echo stripslashes($escaped) . "\n"; // Path: C:\\Users\\Documents
NULL文字の処理
// NULL文字
$text = "Hello\0World";
$escaped = addslashes($text);
echo "元の長さ: " . strlen($text) . "\n"; // 11
echo "エスケープ後の長さ: " . strlen($escaped) . "\n"; // 12
echo "復元後の長さ: " . strlen(stripslashes($escaped)) . "\n"; // 11
実践的な使用例
例1: フォーム入力の処理
class FormDataHandler {
/**
* フォームデータをエスケープ
*/
public static function escapeFormData($data) {
if (is_array($data)) {
return array_map([self::class, 'escapeFormData'], $data);
}
return is_string($data) ? addslashes($data) : $data;
}
/**
* フォームデータを復元
*/
public static function unescapeFormData($data) {
if (is_array($data)) {
return array_map([self::class, 'unescapeFormData'], $data);
}
return is_string($data) ? stripslashes($data) : $data;
}
/**
* magic_quotes_gpc対策
*/
public static function removeMagicQuotes($data) {
// PHP 5.4より前のバージョンでmagic_quotes_gpcが有効な場合の対策
if (is_array($data)) {
return array_map([self::class, 'removeMagicQuotes'], $data);
}
return stripslashes($data);
}
/**
* 安全にデータを取得
*/
public static function getSafeInput($key, $default = '') {
if (!isset($_POST[$key])) {
return $default;
}
$value = $_POST[$key];
// magic_quotes_gpc対策(古いPHPバージョン用)
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
$value = self::removeMagicQuotes($value);
}
return $value;
}
}
// 使用例
$formData = [
'name' => "O'Brien",
'comment' => 'He said, "Hello"',
'path' => 'C:\\Users\\Documents'
];
echo "=== 元のデータ ===\n";
print_r($formData);
// エスケープ
$escaped = FormDataHandler::escapeFormData($formData);
echo "\n=== エスケープ後 ===\n";
print_r($escaped);
// 復元
$restored = FormDataHandler::unescapeFormData($escaped);
echo "\n=== 復元後 ===\n";
print_r($restored);
// 一致確認
var_dump($formData === $restored); // bool(true)
例2: データベース操作
class DatabaseHelper {
/**
* クエリ用にエスケープ(注意: 実際にはPDOやmysqli_real_escape_stringを使用すべき)
*/
public static function escapeForQuery($value) {
return addslashes($value);
}
/**
* データベースから取得したデータを復元
*/
public static function unescapeFromDatabase($value) {
return stripslashes($value);
}
/**
* レコード全体を復元
*/
public static function unescapeRecord($record) {
$unescaped = [];
foreach ($record as $key => $value) {
if (is_string($value)) {
$unescaped[$key] = stripslashes($value);
} else {
$unescaped[$key] = $value;
}
}
return $unescaped;
}
/**
* 複数レコードを復元
*/
public static function unescapeRecords($records) {
return array_map([self::class, 'unescapeRecord'], $records);
}
}
// 使用例
$userData = [
'name' => "O'Connor",
'bio' => 'Developer who loves "coding"',
'company' => 'Tech\\Solutions'
];
echo "=== 元のデータ ===\n";
print_r($userData);
// データベース保存用にエスケープ
$forDb = [];
foreach ($userData as $key => $value) {
$forDb[$key] = DatabaseHelper::escapeForQuery($value);
}
echo "\n=== DB保存用 ===\n";
print_r($forDb);
// データベースから取得したと仮定して復元
$restored = DatabaseHelper::unescapeRecord($forDb);
echo "\n=== 復元後 ===\n";
print_r($restored);
var_dump($userData === $restored); // bool(true)
例3: JSONデータの処理
class JsonHandler {
/**
* JSONエンコード前のエスケープ処理
*/
public static function prepareForJson($data) {
// JSONはバックスラッシュを自動的にエスケープするため、
// 二重エスケープを防ぐ
if (is_array($data)) {
return array_map([self::class, 'prepareForJson'], $data);
}
if (is_string($data)) {
// 既にエスケープされている場合は元に戻す
return stripslashes($data);
}
return $data;
}
/**
* JSONデコード後の処理
*/
public static function processFromJson($data) {
if (is_array($data)) {
return array_map([self::class, 'processFromJson'], $data);
}
return $data;
}
/**
* 安全にJSONエンコード
*/
public static function safeEncode($data) {
$prepared = self::prepareForJson($data);
return json_encode($prepared, JSON_UNESCAPED_UNICODE);
}
/**
* 安全にJSONデコード
*/
public static function safeDecode($json) {
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('JSON decode error: ' . json_last_error_msg());
}
return self::processFromJson($data);
}
}
// 使用例
$data = [
'title' => "Book: \"PHP Guide\"",
'author' => "O'Brien",
'path' => 'C:\\Books\\PHP'
];
// 誤ってエスケープされたデータ
$wrongEscaped = [
'title' => "Book: \\\"PHP Guide\\\"",
'author' => "O\\'Brien",
'path' => 'C:\\\\Books\\\\PHP'
];
echo "=== 正しいデータ ===\n";
$json1 = JsonHandler::safeEncode($data);
echo $json1 . "\n";
echo "\n=== 二重エスケープを修正 ===\n";
$json2 = JsonHandler::safeEncode($wrongEscaped);
echo $json2 . "\n";
// デコード
$decoded = JsonHandler::safeDecode($json2);
print_r($decoded);
例4: ファイルパスの処理
class PathHandler {
/**
* Windowsパスのバックスラッシュを処理
*/
public static function normalizePath($path) {
// 二重バックスラッシュを単一に
return stripslashes($path);
}
/**
* パス配列を正規化
*/
public static function normalizePaths($paths) {
return array_map([self::class, 'normalizePath'], $paths);
}
/**
* パスの結合
*/
public static function joinPath(...$parts) {
$normalized = array_map([self::class, 'normalizePath'], $parts);
return implode(DIRECTORY_SEPARATOR, $normalized);
}
/**
* エスケープされたパスを表示用に整形
*/
public static function formatForDisplay($path) {
$normalized = stripslashes($path);
// バックスラッシュをスラッシュに変換(表示用)
return str_replace('\\', '/', $normalized);
}
}
// 使用例
$paths = [
'C:\\\\Users\\\\Documents',
'D:\\\\Projects\\\\PHP',
'/var/www/html'
];
echo "=== 元のパス ===\n";
print_r($paths);
$normalized = PathHandler::normalizePaths($paths);
echo "\n=== 正規化後 ===\n";
print_r($normalized);
// パス結合
$fullPath = PathHandler::joinPath('C:\\\\Users', 'Documents', 'file.txt');
echo "\n結合パス: " . $fullPath . "\n";
// 表示用フォーマット
echo "表示用: " . PathHandler::formatForDisplay('C:\\\\Users\\\\Documents') . "\n";
例5: CSVデータの処理
class CsvProcessor {
/**
* CSVフィールドからエスケープを除去
*/
public static function unescapeCsvField($field) {
// CSVで二重引用符がエスケープされている場合
$field = str_replace('""', '"', $field);
// その他のバックスラッシュエスケープを除去
return stripslashes($field);
}
/**
* CSV行全体を処理
*/
public static function processCsvLine($line) {
$fields = str_getcsv($line);
return array_map([self::class, 'unescapeCsvField'], $fields);
}
/**
* CSVファイルを読み込んで処理
*/
public static function readCsv($filename) {
if (!file_exists($filename)) {
throw new Exception("ファイルが見つかりません: {$filename}");
}
$lines = file($filename, FILE_IGNORE_NEW_LINES);
$data = [];
foreach ($lines as $line) {
$data[] = self::processCsvLine($line);
}
return $data;
}
/**
* CSVデータをクリーンアップ
*/
public static function cleanCsvData($data) {
$cleaned = [];
foreach ($data as $row) {
$cleanedRow = [];
foreach ($row as $field) {
$cleanedRow[] = self::unescapeCsvField($field);
}
$cleaned[] = $cleanedRow;
}
return $cleaned;
}
}
// 使用例
$csvData = [
["O\\'Brien", "Developer", "He said \\\"Hello\\\""],
["Jane", "Designer", "Path: C:\\\\Work"],
];
echo "=== 元のデータ ===\n";
print_r($csvData);
$cleaned = CsvProcessor::cleanCsvData($csvData);
echo "\n=== クリーンアップ後 ===\n";
print_r($cleaned);
例6: ログファイルの処理
class LogCleaner {
/**
* ログメッセージからエスケープを除去
*/
public static function cleanLogMessage($message) {
return stripslashes($message);
}
/**
* ログファイルを読み込んでクリーンアップ
*/
public static function cleanLogFile($inputFile, $outputFile) {
if (!file_exists($inputFile)) {
throw new Exception("入力ファイルが見つかりません: {$inputFile}");
}
$lines = file($inputFile);
$cleaned = [];
foreach ($lines as $line) {
$cleaned[] = stripslashes($line);
}
return file_put_contents($outputFile, implode('', $cleaned));
}
/**
* ログエントリをパースして復元
*/
public static function parseLogEntry($entry) {
// [timestamp] [level] message 形式を想定
if (preg_match('/^\[(.*?)\] \[(.*?)\] (.+)$/', $entry, $matches)) {
return [
'timestamp' => $matches[1],
'level' => $matches[2],
'message' => stripslashes($matches[3])
];
}
return null;
}
}
// 使用例
$logEntries = [
"[2024-02-23 10:30:00] [ERROR] File not found: C:\\\\Users\\\\file.txt",
"[2024-02-23 10:31:00] [INFO] User \\'admin\\' logged in",
"[2024-02-23 10:32:00] [WARN] Query: \\"SELECT * FROM users\\"",
];
echo "=== 元のログ ===\n";
foreach ($logEntries as $entry) {
echo $entry . "\n";
}
echo "\n=== クリーンアップ後 ===\n";
foreach ($logEntries as $entry) {
$parsed = LogCleaner::parseLogEntry($entry);
if ($parsed) {
echo "[{$parsed['timestamp']}] [{$parsed['level']}] {$parsed['message']}\n";
}
}
例7: コンフィグファイルの処理
class ConfigParser {
/**
* 設定値からエスケープを除去
*/
public static function unescapeValue($value) {
return stripslashes($value);
}
/**
* 設定ファイルを読み込む
*/
public static function parseConfigFile($filename) {
if (!file_exists($filename)) {
throw new Exception("設定ファイルが見つかりません: {$filename}");
}
$lines = file($filename, FILE_IGNORE_NEW_LINES);
$config = [];
foreach ($lines as $line) {
$line = trim($line);
// コメントと空行をスキップ
if (empty($line) || $line[0] === '#') {
continue;
}
// key=value 形式
if (strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);
// エスケープを除去
$config[$key] = self::unescapeValue($value);
}
}
return $config;
}
/**
* 設定ファイルに書き込む
*/
public static function writeConfigFile($filename, $config) {
$lines = [];
foreach ($config as $key => $value) {
// エスケープ
$escapedValue = addslashes($value);
$lines[] = "{$key}={$escapedValue}";
}
return file_put_contents($filename, implode("\n", $lines));
}
/**
* 設定を更新
*/
public static function updateConfig($filename, $key, $value) {
$config = self::parseConfigFile($filename);
$config[$key] = $value;
return self::writeConfigFile($filename, $config);
}
}
// 使用例(ファイルがあると仮定)
/*
# config.ini の内容
app_name=My\\'s App
database_path=C:\\\\Program Files\\\\MySQL
welcome_message=Welcome! \\"Enjoy\\"
$config = ConfigParser::parseConfigFile('config.ini');
print_r($config);
Output:
Array (
[app_name] => My's App
[database_path] => C:\Program Files\MySQL
[welcome_message] => Welcome! "Enjoy"
)
*/
stripcslashes()との違い
// stripslashes(): バックスラッシュのみ除去
$str1 = "Hello\\nWorld";
echo stripslashes($str1) . "\n";
// 出力: Hello\nWorld(\nは解釈されない)
// stripcslashes(): エスケープシーケンスを解釈
$str2 = "Hello\\nWorld";
echo stripcslashes($str2) . "\n";
// 出力:
// Hello
// World(\nが改行に変換される)
// バックスラッシュの除去
$path = "C:\\\\Users\\\\Documents";
echo "stripslashes: " . stripslashes($path) . "\n";
// C:\Users\Documents
echo "stripcslashes: " . stripcslashes($path) . "\n";
// C:\Users\Documents
// 16進数エスケープ
$hex = "\\x48\\x65\\x6C\\x6C\\x6F";
echo "stripslashes: " . stripslashes($hex) . "\n";
// \x48\x65\x6C\x6C\x6F(変化なし)
echo "stripcslashes: " . stripcslashes($hex) . "\n";
// Hello(16進数が解釈される)
注意点と制限事項
magic_quotes_gpcの影響
// PHP 5.4より前のバージョンでの対策
function removeSlashesIfNeeded($data) {
// magic_quotes_gpcが有効な場合のみ処理
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
if (is_array($data)) {
return array_map('removeSlashesIfNeeded', $data);
}
return stripslashes($data);
}
return $data;
}
// 使用例(古いPHPバージョン)
// $_POST = removeSlashesIfNeeded($_POST);
二重エスケープの問題
// 二重エスケープを避ける
$text = "O'Brien";
// 正しい方法
$escaped = addslashes($text); // O\'Brien
$restored = stripslashes($escaped); // O'Brien
// 間違った方法(二重エスケープ)
$doubleEscaped = addslashes($escaped); // O\\\'Brien
$wrongRestore = stripslashes($doubleEscaped); // O\'Brien(元に戻らない)
echo "正しい復元: " . $restored . "\n";
echo "間違った復元: " . $wrongRestore . "\n";
パフォーマンス
// 大量のデータ処理
$data = array_fill(0, 10000, "It\\'s a test");
$start = microtime(true);
$result = array_map('stripslashes', $data);
$time = microtime(true) - $start;
echo "処理時間: {$time}秒\n";
echo "処理件数: " . count($result) . "\n";
現代的な代替手段
// PDOを使用(推奨)
class ModernDatabaseHandler {
private $pdo;
public function __construct($dsn, $username, $password) {
$this->pdo = new PDO($dsn, $username, $password);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
public function insert($name, $bio) {
// プリペアドステートメントを使用(エスケープ不要)
$stmt = $this->pdo->prepare(
"INSERT INTO users (name, bio) VALUES (:name, :bio)"
);
return $stmt->execute([
':name' => $name,
':bio' => $bio
]);
}
}
// htmlspecialchars()を使用(HTML出力用)
function safeHtmlOutput($text) {
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
}
// 使用例
$userInput = "O'Brien said \"Hello\"";
echo safeHtmlOutput($userInput);
// O'Brien said "Hello"
まとめ
stripslashes()関数の特徴をまとめると:
できること:
addslashes()で追加されたバックスラッシュの除去- クォートのエスケープ解除
- パスのバックスラッシュ正規化
処理される文字:
\'→'(シングルクォート)\"→"(ダブルクォート)\\→\(バックスラッシュ)\0→ NULL文字
推奨される使用場面:
- フォーム入力の処理
- レガシーコードのメンテナンス
- magic_quotes_gpc対策(古いPHP)
- パスの正規化
注意点:
- 現代のPHPではPDOやmysqli_real_escape_stringを使用すべき
- magic_quotes_gpcは非推奨(PHP 5.4で削除)
- 二重エスケープに注意
- HTML出力には
htmlspecialchars()を使用
関連関数:
addslashes(): バックスラッシュを追加stripcslashes(): Cスタイルのエスケープを解除htmlspecialchars(): HTML用エスケープmysqli_real_escape_string(): MySQL用エスケープ
現代的な代替手段:
- PDOのプリペアドステートメント
filter_input()htmlspecialchars()
stripslashes()は主にレガシーコードや特定の状況で使用されます。新しいコードでは、PDOなどのより安全な方法を使用することを強く推奨します!
