PHPでは、 Symlink()関数により、開発者はシンボリックリンクを作成できます。これは、ファイルの整理、ショートカットの作成、コンテナに似た仮想ファイルシステム構造の構築など、多くのシナリオで非常に役立ちます。ただし、基礎となるファイルシステムの運用性により、不適切に使用すると、許可の問題やセキュリティリスクさえも引き起こすのは簡単です。
この記事では、開発者がこの機能を安全かつ効率的に使用できるように、実用的なアプリケーションの観点からSymlink()を使用する場合、一般的な許可の問題と解決策に関する詳細な議論を行います。
$target = '/var/www/html/data/original.txt';
$link = '/var/www/html/data/link.txt';
if (symlink($target, $link)) {
echo 'シンボルリンクの作成に成功します。';
} else {
echo 'シンボリックリンクの作成に失敗しました。';
}
使用法は単純で明確ですが、開発者は実際に展開する際に以下の問題に遭遇することがよくあります。
最も一般的な問題は、 symlink()がエラープロンプトなしでfalseを返すことです。根本的な原因は通常:
PHPスクリプト実行ユーザー( www-dataなど)には、ターゲットファイルまたはその優れたディレクトリに適切な権限がありません。
一部のシステム(特にSelinux対応Linuxシステム)は、Symlink()の動作を制限しています。
Windowsプラットフォームの非管理者アカウントには、デフォルトでシンボリックリンクを作成する許可がありません。
PHPユーザーがターゲットパスに「実行」と「書き込み」権限があることを確認してください。
Linuxでは、次のコマンドを使用してアクセス許可を変更できます。
sudo chown -R www-data:www-data /var/www/html/data
sudo chmod -R 755 /var/www/html/data
SELINUXステータスを確認し、対応するポリシー( SetSeBool -P HTTPD_ENABLE_HOMEDIRSを使用するなど)を構成します。
Windowsで開発者モードを有効にするか、管理者としてPHPを実行します。
symlink()を呼び出す前にアクセス許可を確認して、盲目の実行を避けます。
if (is_writable(dirname($link)) && is_readable($target)) {
symlink($target, $link);
} else {
error_log('十分な権限なしでシンボリックリンクを作成します');
}
一部のシステムでは、不規則なパス(相対パスの使用など)のためにリンクの作成を拒否する場合があります。 RealPath()を使用して、パスが正しいことを確認できます。
$target = realpath('/var/www/html/data/original.txt');
$link = '/var/www/html/data/link.txt';
ユーザーが制御するパスがSymlink()に直接参加できるようにしないでください。そうしないと、任意のファイル参照攻撃につながる可能性があります。ホワイトリストの検証を使用して、パスを制限できます。
$allowedDir = '/var/www/html/data/';
$target = realpath($_POST['path']);
if (strpos($target, $allowedDir) === 0) {
symlink($target, $link);
} else {
die('違法な道');
}
ReadLink()またはRealPath()を使用して、リンクターゲットを確認し、 /etc /passwdなどの機密システムファイルを指しないようにしないでください。
$realTarget = realpath($target);
if (strpos($realTarget, '/var/www/html/data/') !== 0) {
die('違法リンクターゲット');
}
リンクの作成には、ファイルシステムの変更が含まれます。例外の追跡を容易にするために、ログを記録することをお勧めします。
file_put_contents('/var/log/link_log.txt', date('c') . " リンクを作成します: $link -> $target\n", FILE_APPEND);
高い並行性または人種条件によって引き起こされる許可の問題を回避するために、 flock()を使用して操作プロセスをロックできます。
$fp = fopen('/tmp/link.lock', 'w+');
if (flock($fp, LOCK_EX)) {
symlink($target, $link);
flock($fp, LOCK_UN);
}
fclose($fp);
環境でSymlink()がまったく許可されていない場合(共有ホスティングなど)、PHPを使用して「論理リンク」を実装し、ジャンプまたはプロキシを通じてシミュレートできます。
header('Location: https://gitbox.net/files/original.txt');
exit;
この方法はシステムレベルのリンクではありませんが、いくつかの要件を実現することができ、権限に関する厳格な要件はありません。