2024 年日本 PHP 會議
新增筆記

使用者貢獻的筆記 19 筆筆記

22
olszewski_marek at yahoo dot com
24 年前
這裡有一個簡單的方法來控制誰下載您的檔案...

您必須設定:$filename、$downloaddir、$safedir 和 $downloadURL。

基本上,$filename 是檔案的名稱,$downloaddir 是您伺服器上的任何目錄,$safedir 是一個無法透過瀏覽器存取的目錄,其中包含一個名為 $filename 的檔案,$downloadURL 是您的 $downloaddir 的 URL 等效項。

此方法的工作原理是,當使用者想要下載檔案時,會在 $downloaddir 中建立一個隨機命名的目錄,並建立一個到所請求檔案的符號連結。 然後瀏覽器會被重新導向到新的連結,並開始下載。

在為自己建立一個符號連結之前,程式碼也會刪除任何過去使用者建立的任何過去的符號連結。 這實際上一次只留下一個符號連結,並防止過去的使用者在不透過此腳本的情況下再次下載檔案。 如果在其他人從該連結下載時刪除了符號連結,似乎沒有問題。

如果沒有很多人下載檔案,這不是太好,因為符號連結將不會被刪除,直到另一個人下載相同的檔案。

無論如何,請享用

<?php
$letters
= 'abcdefghijklmnopqrstuvwxyz';
srand((double) microtime() * 1000000);
$string = '';
for (
$i = 1; $i <= rand(4,12); $i++) {
$q = rand(1,24);
$string = $string . $letters[$q];
}
$handle = opendir($downloaddir);
while (
$dir = readdir($handle)) {
if (
is_dir($downloaddir . $dir)){
if (
$dir != "." && $dir != ".."){
@
unlink($downloaddir . $dir . "/" . $filename);
@
rmdir($downloaddir . $dir);
}
}
}
closedir($handle);
mkdir($downloaddir . $string, 0777);
symlink($safedir . $filename, $downloaddir . $string . "/" . $filename);
Header("Location: " . $downloadURL . $string . "/" . $filename);
?>
4
Wixiweb
6 年前
如果您使用 suhosin 擴充,您必須允許使用
> suhosin.executor.allow_symlink = On

請檢查您的 /var/log/syslog 檔案以取得更多資訊
> suhosin:警告 - 在 open_basedir 期間呼叫了 symlink
10
reddy1042001 at yahoo dot co dot in
14 年前
Windows 上的符號連結由 Symlink() 建立,它只接受絕對路徑而不接受相對路徑。 Windows 上的相對路徑不支援符號連結
4
Anonymous
17 年前
嗯,廢話...這就是我對之前筆記要說的全部。 請刪除它。 :)

Windows Vista 現在有自己的符號連結程式 (mklink)。 希望未來 Windows 版的 PHP 會放入此功能?

無論如何,這將在 Vista 上運作(假設您的 PHP 使用者具有適當的權限)
<?php
define
('SYMLINK_FILE', 0);
define('SYMLINK_DIR', 1);
define('SYMLINK_JUNCTION', 2);
function
symlink ($target, $link, $flag = SYMLINK_FILE) {
switch (
$flag) {
case
SYMLINK_DIR: $pswitch = '/d'; break;
case
SYMLINK_JUNCTION: $pswitch = '/j'; break;
case
SYMLINK_FILE:
default:
$pswitch = ''; break;
}
// 將 / 變更為 \,否則會出錯。
$target = str_replace('/', '\\', $target);
$link = str_replace('/', '\\', $link);
return
exec('mklink ' . $pswitch . ' "' . $link . '" "' . $target . '"');
}
?>
2
Numien
17 年前
使用符號連結來控制檔案存取與使用 readfile() 的一個差異是,HTTP 伺服器會自動處理符號連結的內容類型。

如果您總是希望它被下載,這可能是一個缺點。然而,如果您希望在瀏覽器中查看非預定義類型的檔案,這可能是一個真正的優勢。

當然,您可以使用 fileinfo/mime-magic 來執行此操作,但這些需要模組,而這些模組並非總是在共享主機上可用。
5
zeomniscient
10 年前
背景:Windows 作業系統上的 php cli。

不要忘記以「以系統管理員身分執行」啟動主控台,否則符號連結將會傳回 'false' 並引發以下錯誤
警告:symlink():無法建立符號連結,錯誤碼 (1314)
2
flobee
9 年前
我喜歡使用相對的符號/硬連結,但在錯誤思考時並非那麼容易 :-)
manpage 說明:目標是 _linkname_,從那一點開始成功建立相對連結,必須從應該建立連結的目錄開始,例如:
/myfiles/now/here/
/myfiles/links/

chdir( realpath(dirname($target)));
您需要建立/找出來源的相對路徑,否則將在連結中使用絕對路徑。

如果您從來源開始建立目標路徑,例如
「/myfiles/now/here/../../later/」且連結應指向 /myfiles/later/,則您需要使用 realpath( dirname() ),使用 chdir() 設定新位置,並從這裡開始連結到來源,即 ../now/here/
例如,當您擁有來源和目標的絕對路徑時,可以找出這點
$dirTo = realpath(dirname($to));
chdir($dirTo);
$linkName = basename($to);
$target = $dirTo . DIRECTORY_SEPARATOR . $linkName;
$srcFile = getRelativeDirectory($from, $to); //基本上是一個函式,會找出從 -> 到,但在這種情況下,from 是您需要開始的目標。
在下方您可以找到一些範例,說明如何將路徑分割成區塊以找出相對路徑
2
anything at the domain williamfrantz.com
18 年前
Olszewski_marek 提出了一個很好的建議,但 readfile() 函式也可以用來模糊最終使用者下載的檔案。

/* 設定將要傳送的檔案 */
$downloadDir = "some/secret/directory/";
$file = "theFileName.dat";

/* IE 需要此設定,否則 Content-disposition 會被忽略 */
if(ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off');

/* 輸出強制顯示「另存新檔」對話方塊的 HTTP 標頭 */
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\\"$file\\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".@filesize($downloadDir.$file));

/* 防止指令碼因為大型檔案而逾時 */
set_time_limit(0);

/* 使用 @ 傳送整個檔案以忽略所有錯誤 */
@readfile($downloadDir.$file);

/* 立即結束,使檔案內容後方不會跟隨任何垃圾 */
exit;
1
alvaro at demogracia dot com
6 年前
若要移除符號連結,您需要使用

- Windows 上的 rmdir()
- 其他地方的 unlink()

<?php
function removeSymlink($path) {
if (
PHP_SHLIB_SUFFIX==='dll') {
return
rmdir($path);
}
return
unlink($path);
}
1
raat1979 at gmail dot com
9 年前
請注意,至少在 Windows 2008 R2 上使用 php 5.3 時,符號連結函式會受到 statcache 的影響。

我收到了錯誤 183,表示連結已存在。雖然符號連結實際上已被另一個程序移動到不同的位置,而且肯定不再存在。
使用檔名呼叫 clearstatcache 無效。很可能因為檔名已轉換為裝置路徑(例如,「\Device\HarddiskVolume1\D-Drive\www\pp\#static\index.html」),這是 Windows 呼叫的要求。

最簡單的方法就是直接呼叫沒有檔名的 clearstatcache 以解決此問題。

如果您真的想使用檔名呼叫 clearstatcache,您可以對已刪除(但仍存在於 statcache 中)的符號連結使用 readlink,以取得檔名。
例如,類似以下內容
<?php
if(@symlink('d:/www/pp/#static/index.html','d:/www/index.html')===false){
//連結失敗,也許是 statcache 問題?我們嘗試取得目標,如果是 statcache 問題,這應該可以正常運作

if(($rl = @readlink($target))===false) return false; //不是快取問題,因為對不存在的檔案執行 stat 失敗,一定有其他問題...

//清除實際目標的 stat 快取,奇怪的是,即使這是目標,而不是要建立的符號連結 (*),這仍然有效
clearstatcache(true,$rl);

if(@
symlink($source,$target) ===false) return false; //無法建立符號連結
?>

*在 Windows 上,PHP 似乎是在目標上維護 statcache,而不是在實際的符號連結上(這有助於取得檔案屬性並限制 statcache 的大小)
1
Anonymous
18 年前
<?

/**
* 在 Windows 上模擬符號連結的函式。
* 使用 junction 公用程式,可在
* http://www.sysinternals.com 取得
* 請注意,這只適用於 NTFS 磁碟區。
*
* junction 公用程式的語法為
* junction <連結目錄> <連結目標>
*
* 請注意,Junction 命令的參數順序
* 與符號連結函式相反!
*
* @param string $target
* @param string $link
*/
function _symlink( $target, $link ) {
if ($_SERVER['WINDIR'] || $_SERVER['windir']) {
exec('junction "' . $link . '" "' . $target . '"');
} else {
symlink($target,$link);
}
}

function _unlink($link ) {
if ($_SERVER['WINDIR'] || $_SERVER['windir']) {
exec('junction -d "' . $link . '"');
} else {
unlink($link);
}
}
?>
1
Calin
12 年前
在 IIS(網際網路資訊服務)上,您需要設定權限以允許建立符號連結。

前往「本機安全性原則」->「本機原則」->「使用者權限指派」,然後在「建立符號連結」上按一下滑鼠右鍵 ->「內容」->「新增使用者或群組」,然後新增 "IUSR" 使用者,這應該是與 IIS 相關聯的使用者。
可能需要重新啟動。

如果這不起作用,請前往 IIS 管理員 ->「驗證」-> 選取「匿名驗證」->「編輯」,然後輸入您目前登入的使用者,這應該是管理員。
按一下「確定」,現在 php 中的 symlink() 函式應該可以正常運作。
0
php-user at protonmail dot com
1 年前
沒有記載的一件事是,此函式會檢查目標檔案是否存在。如果您想要建立數個指向本機掛載的遠端檔案的符號連結(例如使用 Rclone),這種行為可能會非常不方便。在這種特定情況下,此函式可能需要 2 秒甚至更長的時間才能完成。
0
Scare!
2 年前
在 Windows 上,symlink() 不接受路徑中包含符號連結的路徑。請先使用 realpath() https://php.dev.org.tw/manual/en/function.realpath.php 展開路徑。
0
lingtalfi
10 年前
如果 symlink 似乎無法正確運作,請嘗試將目標引數定義為絕對路徑。
在 MacOsX PHP5.5 上撰寫程式碼時,我注意到在某些情況下,在目標引數上使用絕對路徑是我可以建立正確符號連結的唯一方法。
0
ewering at gmail dot com
17 年前
此函式有時會無緣無故地無法運作,傳回 FALSE 且不建立符號連結。使用 exec('ln -s source dest') 執行相同的動作可以完美運作。我建議使用後者。
-2
Porjo
15 年前
請記住,當使用共用檔案系統(例如 NFS)時,您可能不想要使用絕對路徑建立符號連結,例如:

在 Server1 上,您正在執行一個 PHP 指令碼,該指令碼需要在 localhost 上掛載的 NFS 共用資料夾 /mnt/nfs/widgets 內建立一個名為 widget2 的符號連結,該連結連到 widget1

在 Server2 上,這個相同的 NFS 共用資料夾掛載在 /usr/local/widgets 下

如果您在 Server1 上使用絕對路徑,那麼 Server2 會嘗試參照 /mnt/nfs/widgets/widget1,但它將無法找到...

您需要先 cd 進入目錄,然後再建立連結 - 這樣連結才會是相對的。除非您從建立符號連結的相同目錄執行 PHP 腳本,否則您無法使用 symlink()。請改用 exec(),如下所示:

<?php

exec
("cd <nfs 掛載路徑>; ln -s <目標> <連結名稱>");

?>
-2
contact at tcknetwork dot com
19 年前
為了讓您的程式碼在 Unix 和 Win32 上都能移植,請執行以下操作:
1. 下載 http://www.dynawell.com/reskit/microsoft/win2000/linkd.zip
2. 解壓縮,將 linkd.exe 放在 C:\Windows\System32 或 C:\WINNT\System32
3. 在您的程式碼中包含以下內容:
<?
function _syslink($t /*目標*/ ,$l /*連結*/ ) {
if ($_SERVER["WINDIR"]) {
$p=dirname($_SERVER["SCRIPT_FILENAME"])."/";
exec("linkd ".$p.$t." ".$p.$l);
} else syslink($t,$l);
}
function _unlink($l /*連結*/ ) {
if ($_SERVER["WINDIR"]) {
$p=dirname($_SERVER["SCRIPT_FILENAME"])."/";
exec("linkd ".$p.$l." /D");
} else unlink($l);
}
?>
4. 盡情享用
_symlink(目標, 連結) 的作用類似於 *nix 上的 symlink()
_unlink(連結) 用於正確刪除建立的連結
-2
匿名
18 年前
Olszewski 看起來不錯,但為了稍微提高安全性,他的腳本的第五行應該讀作
<?
...
$q = rand(1,26);
...
?>

而不是 rand(1,24)。
To Top