Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : Filesystem Functions : symlink

symlink

Creates a symbolic link (PHP 4, PHP 5)
bool symlink ( string target, string link )


Code Examples / Notes » symlink

12-apr-2007 02:44

Um, duh... that's all I gotta say about by previous note. Please delete it. :)
Windows Vista has its own symlink program now (mklink). Hopefully future versions of PHP for Windows will have this function put it?
Anyway, this will work on Vista (assuming your PHP user has the proper permissions):
<?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;
   }
   // Change / to \ because it will break otherwise.
   $target = str_replace('/', '\\', $target);
   $link = str_replace('/', '\\', $link);
   return exec('mklink ' . $pswitch . ' "' . $link . '" "' . $target . '"');
}
?>


contact

To make your code portable on unix AND win32, do the following
1. Download http://www.dynawell.com/reskit/microsoft/win2000/linkd.zip
2. Unzip, put linkd.exe in C:\Windows\System32 or C:\WINNT\System32
3. Include in your code the following
<?
function _syslink($t /*target*/ ,$l /*link*/ ) {
if ($_SERVER["WINDIR"]) {
 $p=dirname($_SERVER["SCRIPT_FILENAME"])."/";
 exec("linkd ".$p.$t." ".$p.$l);
} else syslink($t,$l);
}
function _unlink($l /*link*/ ) {
if ($_SERVER["WINDIR"]) {
 $p=dirname($_SERVER["SCRIPT_FILENAME"])."/";
 exec("linkd ".$p.$l." /D");
} else unlink($l);
}
?>
4. Enjoy
_symlink(TARGET,LINK) works like symlink() on *nix
_unlink(LINK) to delete properly the link created


veronique

This might sound obvious, but sometimes these details slip from our minds...
Make sure the directory in which you are trying to create the symbolic link (AND the directory you are trying to link to in the case of directory linking) has the proper permissions, or you will get a "permission denied" from PHP. If you use for example,
echo shell_exec("ln -sv $target $name")
you might get the correct "link created" message, but without the link being actually created.
It's probably the same thing with hard links, I just haven't tried it.


numien

The one difference to using symlinks for controlled file access vs. readfile() is that the HTTP server will handle content-type of the symlink automatically.
If you always want it to be downloaded, this can be a negative point. However, if you want a file of non-predefined type to be viewable in the browser, this can be a real asset.
Of course, you can use fileinfo/mime-magic to do that, but those require a module which isn't always available on shared hosting.


johnw

tcknetwork dot com's solution for Win32 seemed attractive but darned if I could make it work so there seem to be some further notes needed. One obvious problem is in the line:
exec("linkd ".$p.$t." ".$p.$l);
Note that since $p (from the line above) is the absolute path to the directory of the current script, the $t and $l are only defined relative to that path. And should not contain any spaces. I tried putting single quotes around the link and target but it didn't help.


anything

Olszewski_marek makes a good suggestion, but the readfile() function can also be used to obscure file downloads from end users.
/* Setup the file that will be sent */
$downloadDir = "some/secret/directory/";
$file = "theFileName.dat";
/* Required for IE, otherwise Content-disposition is ignored */
if(ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off');
/* Output HTTP headers that force "Save As" dialog */
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));
/* Prevent the script from timing out for large files */
set_time_limit(0);
/* Send the entire file using @ to ignore all errors */
@readfile($downloadDir.$file);
/* Exit immediately so no garbage follows the file contents */
exit;


aircha

Olszewski's method of creating downloadable links on the fly is pretty good.
I use a different technique under Apache where if you want a file, you might use a url like:
mydomain.com/files/mysecretfile.doc
But in fact Apache redirects this to a script with a url like:
mydomain.com/utilities/downloadfile.php?filename=mysecretfile.doc
(The browser address bar will still show the first url).
The script downloadfile.php can then handle all the mucky stuff like checking session variables to see if someone is logged on, whether they have access to mysecretfile.doc, and if you want to encrypt before download.
An advantage of this is that the php code to achieve the equivalent of Olszewski's is shorter, so might execute faster. But more importantly, a casual hacker might think all he has to do is find myverysecurefile.doc under the /home/user/public_html/files/mysecretfile.doc, or copy the url - but there's nothing there! He won't find it or get an Apache error page.


29-dec-2005 03:21

Olszewski seems pretty good, but just to boost the security a bit, the fifth line of his script should read
<?
...
   $q = rand(1,26);
...
?>
instead of rand(1,24).


olszewski_marek

Here is a simple way to control who downloads your files...
You will have to set: $filename, $downloaddir, $safedir and $downloadURL.
Basically $filename is the name of a file, $downloaddir is any dir on your server, $safedir is a dir that is not accessible by a browser that contains a file named $filename and $downloadURL is the URL equivalent of your $downloaddir.
The way this works is when a user wants to download a file, a randomly named dir is created in the $downloaddir, and a symbolic link is created to the file being requested.  The browser is then redirected to the new link and the download begins.
The code also deletes any past symbolic links created by any past users before creating one for itself.  This in effect leaves only one symbolic link at a time and prevents past users from downloading the file again without going through this script.  There appears to be no problem if a symbolic link is deleted while another person is downloading from that link.
This is not too great if not many people download the file since the symbolic link will not be deleted until another person downloads the same file.
Anyway enjoy:
$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);


stephen

Faking Symlinks on Windows (Win2K + NTFS)
Every once in a while I'll bang my head against something really difficult. I needed to make symlinks, Windows won't let me. The workaround is a couple files in the Win2K Resource Kit called linkd.exe and delrp.exe
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q205524
It only works on folders as far as I can tell, there is another program from SysInternals called Junction which will do both (although I only had success with files, not folders).
http://www.sysinternals.com/ntw2k/source/misc.shtml#junction
I hope this helps those who have experienced this same problem. One step closer to portable applications :)


04-nov-2006 12:33

<?
/**
* A function to emulate symbolic links on Windows.
* Uses the junction utility available at:
* http://www.sysinternals.com
* Note that this will only work on NTFS volumes.
*
* The syntax of the junction utility is:
* junction <junction directory> <junction target>
*
* Note that the parameter order of the Junction command
* is the reverse of the symlink function!
*
* @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);
 }
}
?>


Change Language


Follow Navioo On Twitter
basename
chgrp
chmod
chown
clearstatcache
copy
delete
dirname
disk_free_space
disk_total_space
diskfreespace
fclose
feof
fflush
fgetc
fgetcsv
fgets
fgetss
file_exists
file_get_contents
file_put_contents
file
fileatime
filectime
filegroup
fileinode
filemtime
fileowner
fileperms
filesize
filetype
flock
fnmatch
fopen
fpassthru
fputcsv
fputs
fread
fscanf
fseek
fstat
ftell
ftruncate
fwrite
glob
is_dir
is_executable
is_file
is_link
is_readable
is_uploaded_file
is_writable
is_writeable
lchgrp
lchown
link
linkinfo
lstat
mkdir
move_uploaded_file
parse_ini_file
pathinfo
pclose
popen
readfile
readlink
realpath
rename
rewind
rmdir
set_file_buffer
stat
symlink
tempnam
tmpfile
touch
umask
unlink
eXTReMe Tracker