Если вдруг кому-нибудь прийдётся писать что-либо на PHP и в особенности, если будет необходимость запускать внешние программы для каких-либо целей, то следующее руководство для вас.
Имеем: Windows 2003 Server + Internet Information Server 6.0 + PHP 5.0
Задача: Необходимость создать хардлинк (от англ. hard link - жёсткая ссылка) на файл, находящийся на отличной от расположения директории "Inetpub" партиции.
Что такое жёсткая ссылка? В общем-то, как я понял, после кошмарного количества убитого времени, это дополнительное имя файла, на который она ссылается. Точнее сказать, жёсткая ссылка следит не за именем файла, а за закреплённым за файлом идентификатором (в UNIX-системах этот идентификатор назывется inode). Недостатком этого рода ссылок является то, что они живут только в пределах одной партиции, одной файловой системы, так как на каждом разделе жёсткого диска имеется своя собственная, независимая ФС, которая и присваивает всем файлам свои ID, в независимости от того, какие ID были присвоены файлам на другой партиции. Недостатком номер два является невозможность создавать ссылки на директории, обьяснения этому я так и не нашёл.
Почему именно hardlink? Да потому что Windows 2003 Server не в состоянии создать обыкновенную символьную ссылку через консоль. Вот и приходится извращаться как только можно.
Скрипт, в общем-то, совершенно простой, но для того, чтобы заставить его работать, пришлось снова потанцевать с бубном вокруг монитора.
[показать]
// Генерируем строку длинной 32 символа, состоящую из символов указанных в переменной $letters
$letters = 'abcdef0123456789';
srand((double) microtime() * 1000000);
$string = '';
for ($i = 1; $i <= rand(32,32); $i++) {
$q = rand(1,12);
$string = $string . $letters[$q];
}
// Файл, для которого будет создан хардлинк
$file = "F:\\archive\\somefile.mpeg";
// Адрес, где будет создан хардлинк и под каким именем
$hlink = "F:\\tmpfiles\\$string\\somefile.mpeg";
// Создаём директорию с именем $string
if(!exec("mkdir \"F:\\tmpfiles\\$string\"",$status_dir,$error_dir)){
echo "Не могу создать директорию \"F:\\tmpfiles\\$string\"
";
}else{
echo "Директория \"F:\\tmpfiles\\$string\" создана!
";
}
if($error_dir) print_r($status_dir);
// Создаём хардлинк
if(!exec("fsutil hardlink create $hlink $file",$status,$error)){
echo "Не могу создать хардлинк!
";
}else{
echo "Хардлинк создан!
";
}
if($error) print_r($status);
При настройках по умолчанию, такой скрипт выдаст следующие радостные строки:
Не могу создать директорию "F:\tmpfiles\fae72cba8a3bacb8a3b892"
Array ( )
Не могу создать хардлинк!
Array ( )
Вот такие вот сообщения и два пустых массива.
На Windows XP Professional Corporate Edition with Service Pack 2 + Denwer 2.0 хардлинк создаётся. На Windows 2003 Server with Service Pack 3 - нет. Причём, если написать тоже самое в консоли серверной версии Windows (mkdir "F:\tmpfiles\fae72cba8a3bacb8a3b892\", fsutil hardlink create "F:\tmpfiles\fae72cba8a3bacb8a3b892\somefile.mpeg" "F:\archive\somefile.mpeg"), то и директория и линк будут созданы без проблем с сообщением "Hardlink created for D:\temp\link.to.file.avi <<===>> D:\files\file.avi".
В чём же дело? Сперва, нужно проверить не работает ли PHP в безопастном режиме, когда он намерено ограничивает свой функционал. Проявляется это в отказе в работе функций exec(), system(), passthru() и появлении сообщения:
Warning: SAFE MODE Restriction in effect...
Для этого открываем файл %windir%\php.ini, ищём строку safe_mode = On, и изменяем эту директриву на Off. Затем сохраняем файл и перезагружаем web-сервисы. Радуйтесь, если это поможет!
В противном случае, пытаемся заменить exec() на system(), добавить в самое начало команды start (start mkdir...), попытаться поразному экранировать слеши. Ежели и это бессильно перед вашими проблемами, то вам на следующей абзац.
Else - дело в правах. Кому нужно что раздать? IUSR'y права на чтение папки archive и права на запись в папку tmpfiles? Или на выполнение программы fsutil? Чёрт его знает. Что я только не пробывал. Как не мучался. Оказалось всё гораздо проще!
Нужно было дать права IUSR (Internet Guest Account) на исполнение %windir%/system32/cmd.exe!
Но, если будет сделан только этот шаг, то вы получите следующую ошибку:
Array ( [0] => The FSUTIL utility requires that you have administrative privileges. )
Поэтому, IUSR нужно наделить урезанными правами администратора.
Если же необходимо создавать ссылки на директории, то можно использовать вот эту программу:
http://www.sysinternals.com/Utilities/Junction.html