Filesystem 函数
在线手册:中文  英文

chmod

(PHP 4, PHP 5)

chmod改变文件模式

说明

bool chmod ( string $filename , int $mode )

尝试将 filename 所指定文件的模式改成 mode 所给定的。

参数

filename

文件的路径。

mode

注意 mode 不会被自动当成八进制数值,而且也不能用字符串(例如 "g+w")。要确保正确操作,需要给 mode 前面加上 0:

<?php
chmod
("/somedir/somefile"755);   // 十进制数,可能不对
chmod("/somedir/somefile""u+rwx,go+rx"); // 字符串,不对
chmod("/somedir/somefile"0755);  // 八进制数,正确的 mode 值
?>

mode 参数包含三个八进制数按顺序分别指定了所有者、所有者所在的组以及所有人的访问限制。每一部分都可以通过加入所需的权限来计算出所要的权限。数字 1 表示使文件可执行,数字 2 表示使文件可写,数字 4 表示使文件可读。加入这些数字来制定所需要的权限。有关 UNIX 系统的文件权限可以阅读手册“man 1 chmod”和“man 2 chmod”。

<?php
// Read and write for owner, nothing for everybody else
chmod("/somedir/somefile"0600);

// Read and write for owner, read for everybody else
chmod("/somedir/somefile"0644);

// Everything for owner, read and execute for others
chmod("/somedir/somefile"0755);

// Everything for owner, read and execute for owner's group
chmod("/somedir/somefile"0750);
?>

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE

注释

Note:

当前用户指的是执行 PHP 的用户。很可能和通常的 shell 或者 FTP 用户不是同一个。在大多数系统下文件模式只能被文件所有者的用户改变。

Note: 此函数不能作用于远程文件,被检查的文件必须是可通过服务器的文件系统访问的。

Note:

安全模式打开的时候,PHP 会检查所操作的文件是否和正在执行的脚本具有相同的 UID (所有者)。要注意的是,不能修改 SUID,SGID 和 sticky bits。

参见


Filesystem 函数
在线手册:中文  英文

用户评论:

h dot kuppens at cs dot ru dot nl (2011-08-29 02:51:57)

For recursive chmod'ing both files and directories in one step you can use the function below. Note that this function has one argument for directory permissions and one for file permissions.
In this way you can apply the 'x' permission on directories, and skip it on directories. This function also skips links.

Example usage :

   chmod_R( 'mydir', 0666, 0777);

Makes all files and directories within mydir/ directory accessible for everyone, but doesn't make the files executable.

I guess for very deeply nested directories the recursion with php can become problematic, but I can be wrong because I never investigated this.

<?php
function chmod_R($path$filemode$dirmode) {
    if (
is_dir($path) ) {
        if (!
chmod($path$dirmode)) {
            
$dirmode_str=decoct($dirmode);
            print 
"Failed applying filemode '$dirmode_str' on directory '$path'\n";
            print 
"  `-> the directory '$path' will be skipped from recursive chmod\n";
            return;
        }
        
$dh opendir($path);
        while ((
$file readdir($dh)) !== false) {
            if(
$file != '.' && $file != '..') {  // skip self and parent pointing directories
                
$fullpath $path.'/'.$file;
                
chmod_R($fullpath$filemode,$dirmode);
            }
        }
        
closedir($dh);
    } else {
        if (
is_link($path)) {
            print 
"link '$path' is skipped\n";
            return;
        }
        if (!
chmod($path$filemode)) {
            
$filemode_str=decoct($filemode);
            print 
"Failed applying filemode '$filemode_str' on file '$path'\n";
            return;
        }
    }
}
?>

Andrey P. (2011-03-01 14:23:59)

I was trying to change permissions of a folder with chmod command with FTP connection. (I needed a writable folder to upload pictures with php)
I got the following respond:
"SITE CHMOD 777 uploads: command not understood"
The reason: Server is running under Windows system that does not allow to set file permissions via FTP. Conversely, the UNIX-running servers allow that.
Solutions:
1. If your web hosting provider has a web-based control panel that lets you set file permissions, then you need to login there and make changes.
2. It is possible to contact the hosting provider and ask them about this issue; maybe they can make the changes.
3. It is possible to change the hosting provider that has servers run on UNIX, and keep the site there.

MethodicalFool (2010-09-02 09:46:49)

BEWARE, a couple of the examples in the comments suggest doing something like this:
chmod(file_or_dir_name, intval($mode, 8));
However, if $mode is an integer then intval( ) won't modify it. So, this code...
$mode = 644;
chmod('/tmp/test', intval($mode, 8));
...produces permissions that look like this:
1--w----r-T
Instead, use octdec( ), like this:
chmod(file_or_dir_name, octdec($mode));
See also: http://www.php.net/manual/en/function.octdec.php

Geoff W (2010-02-08 02:13:49)

BEWARE using quotes around the second parameter...
If you use quotes eg
chmod (file, "0644");
php will not complain but will do an implicit conversion to an int before running chmod. Unfortunately the implicit conversion doesn't take into account the octal string so you end up with an integer version 644, which is 1204 octal

shelby at coolpage dot com (2009-11-21 04:10:18)

Apparently there is a way to emulate chmod on Windows:
http://www.php.net/manual/en/function.chmod.php#68384
http://neosmart.net/dl.php?id=4
Apparently the way the above works is that Windows has file permissions and they are more complex. To access them, turn off (uncheck) Windows Explorer -> Tool menu -> File Options -> View -> Use simple sharing. Then right-click any file or folder, to access the Security tab. This is known as Windows ACL (access control layer?). You may turn on (check) Use simple sharing again after making any settings to Security and these settings will be retained. You may need to be logged on as a user in the Administrators group to access some permissions on some files, i.e. User Accounts in Control Panel and see Start menu -> Run -> lusrmgr.msc and gpedit.msc.

david at ordal dot com (2009-08-03 12:24:36)

An improvement on the recursive chmod from nicolas@infosoft.... in July 2008. This is a little shorter and should handle all types of linux filesystem files.

<?php
function chmodr($path$filemode) { 
    if (!
is_dir($path)) 
        return 
chmod($path$filemode); 

    
$dh opendir($path); 
    while ((
$file readdir($dh)) !== false) { 
        if(
$file != '.' && $file != '..') { 
            
$fullpath $path.'/'.$file
            if(
is_link($fullpath)) 
                return 
FALSE
            elseif(!
is_dir($fullpath) && !chmod($fullpath$filemode)) 
                    return 
FALSE
            elseif(!
chmodr($fullpath$filemode)) 
                return 
FALSE
        } 
    } 

    
closedir($dh); 

    if(
chmod($path$filemode)) 
        return 
TRUE
    else 
        return 
FALSE
}
?>

Meaulnes Legler (2009-07-10 07:38:34)

Another converter from 'rwx' mode to octal, but considering the setuid/setgid and sticky bits, too. Also the reverse function, converts from octal to 'rwx' mode. Both ignore the leading 'd' or '-' since no directory nor file information is provided.

<?php
function ModeRWX2Octal($Mode_rwx) {    // enter rwx mode, e.g. 'drwxr-sr-x'
    
if ( ! preg_match("/[-d]?([-r][-w][-xsS]){2}[-r][-w][-xtT]/"$Mode_rwx) )
        die(
"wrong <TT>-rwx</TT> mode in ModeRWX2Octal('<TT>$Mode_rwx</TT>')");
    
$Mrwx substr($Mode_rwx, -9);    // 9 chars from the right-hand side
    
$ModeDecStr     = (preg_match("/[sS]/",$Mrwx[2]))?4:0;    // pick out sticky 
    
$ModeDecStr    .= (preg_match("/[sS]/",$Mrwx[5]))?2:0;    // _ bits and change
    
$ModeDecStr    .= (preg_match("/[tT]/",$Mrwx[8]))?1:0;    // _ to e.g. '020'
    
$Moctal     $ModeDecStr[0]+$ModeDecStr[1]+$ModeDecStr[2];    // add them
    
$Mrwx str_replace(array('s','t'), "x"$Mrwx);    // change execute bit 
    
$Mrwx str_replace(array('S','T'), "-"$Mrwx);    // _ to on or off
    
$trans = array('-'=>'0','r'=>'4','w'=>'2','x'=>'1');    // prepare for strtr
    
$ModeDecStr    .= strtr($Mrwx,$trans);    // translate to e.g. '020421401401'
    
$Moctal    .= $ModeDecStr[3]+$ModeDecStr[4]+$ModeDecStr[5];    // continue 
    
$Moctal    .= $ModeDecStr[6]+$ModeDecStr[7]+$ModeDecStr[8];    // _ adding 
    
$Moctal    .= $ModeDecStr[9]+$ModeDecStr[10]+$ModeDecStr[11];  // _ triplets
    
return $Moctal;    // returns octal mode, e.g. '2755' from above.
}
function 
ModeOctal2rwx($ModeOctal) { // enter octal mode, e.g. '644' or '2755'
    
if ( ! preg_match("/[0-7]{3,4}/"$ModeOctal) )    // either 3 or 4 digits
        
die("wrong octal mode in ModeOctal2rwx('<TT>$ModeOctal</TT>')");
    
$Moctal = ((strlen($ModeOctal)==3)?"0":"").$ModeOctal;    // assume default 0
    
$Mode3 substr($Moctal,-3);    // trailing 3 digits, no sticky bits considered
    
$RWX = array ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');    // dumb,huh?
    
$Mrwx $RWX[$Mode3[0]].$RWX[$Mode3[1]].$RWX[$Mode3[2]];    // concatenate
    
if (preg_match("/[1357]/"$Moctal[0])) $Mrwx[8] = ($Mrwx[8]=="-")?"T":"t";
    if (
preg_match("/[2367]/"$Moctal[0])) $Mrwx[5] = ($Mrwx[5]=="-")?"S":"s";
    if (
preg_match("/[4567]/"$Moctal[0])) $Mrwx[2] = ($Mrwx[2]=="-")?"S":"s";
    return 
$Mrwx;    // returns e.g. 'rw-r--r--' or 'rwxr-sr-x'
}
?>

following test code returns the results below

<?php
$Mode 
"-rw-rw-r--";
echo 
"<BR>ModeRWX2Octal(<TT>$Mode) -&gt;</TT> ".ModeRWX2Octal($Mode)."\n";
$Mode "drwxr-sr-x";
echo 
"<BR>ModeRWX2Octal(<TT>$Mode) -&gt;</TT> ".ModeRWX2Octal($Mode)."\n";
$Mode "644";
echo 
"<BR>ModeOctal2rwx($Mode) <TT>-&gt; ".ModeOctal2rwx($Mode)."</TT>\n";
$Mode "2755";
echo 
"<BR>ModeOctal2rwx($Mode) <TT>-&gt; ".ModeOctal2rwx($Mode)."</TT>\n";
?>

ModeRWX2Octal(-rw-rw-r--) -> 0664 
ModeRWX2Octal(drwxr-sr-x) -> 2755 
ModeOctal2rwx(644) -> rw-r--r-- 
ModeOctal2rwx(2755) -> rwxr-sr-x

sander (2009-06-25 11:06:02)

if you want to chmod directories too, use this 

<?php
$iterator 
= new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathname), RecursiveIteratorIterator::SELF_FIRST);

foreach(
$iterator as $item) {
    
chmod($item$filemode);
}
?>

Anonymous (2009-06-24 08:05:55)

Just wanted to point out that the RecursiveIteratorIterator method below won't chmod directories, it only catches files. I haven't been able to find a way to change it so that it catches directories too yet.

Anonymous (2008-12-24 02:14:51)

Changes file mode recursive in $pathname to $filemode

<?php

$iterator 
= new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathname));

foreach(
$iterator as $item) {
    
chmod($item$filemode);
}

?>

nicolas at infosoft dot inf dot br (2008-07-07 05:37:58)

I use the code of haasje@welmers.net, but have a lite alteration. (linux symlink)

<?php
function chmod_R($path$filemode) {
    if (!
is_dir($path))
        return 
chmod($path$filemode);

    
$dh opendir($path);
    while ((
$file readdir($dh)) !== false) {
        if(
$file != '.' && $file != '..') {
            
$fullpath $path.'/'.$file;
            if(
is_link($fullpath))
                return 
FALSE;
            elseif(!
is_dir($fullpath))
                if (!
chmod($fullpath$filemode))
                    return 
FALSE;
            elseif(!
chmod_R($fullpath$filemode))
                return 
FALSE;
        }
    }

    
closedir($dh);

    if(
chmod($path$filemode))
        return 
TRUE;
    else
        return 
FALSE;
}
?>
thanks alls

paul maybe at squirrel mail org (2008-04-24 05:09:50)

Note that info at rvgate dot nl's chmodnum function produces INCORRECT results.  The resutls are base-10 numbers that only LOOK like they are octal numbers.  The function also ignores setuid, setgid and sticky bits, and will produce incorrect numbers if such a file is encountered.  Instead, this brute-force code works.  Maybe there is something more slick, but this isn't too CPU-intensive (note that it assumes you've error-checked that you indeed have a 10-character string!):

<?php
      $permissions 
'drwxr-xr-x';  // or whatever
      
$mode 0;

      if (
$permissions[1] == 'r'$mode += 0400;
      if (
$permissions[2] == 'w'$mode += 0200;
      if (
$permissions[3] == 'x'$mode += 0100;
      else if (
$permissions[3] == 's'$mode += 04100;
      else if (
$permissions[3] == 'S'$mode += 04000;

      if (
$permissions[4] == 'r'$mode += 040;
      if (
$permissions[5] == 'w'$mode += 020;
      if (
$permissions[6] == 'x'$mode += 010;
      else if (
$permissions[6] == 's'$mode += 02010;
      else if (
$permissions[6] == 'S'$mode += 02000;

      if (
$permissions[7] == 'r'$mode += 04;
      if (
$permissions[8] == 'w'$mode += 02;
      if (
$permissions[9] == 'x'$mode += 01;
      else if (
$permissions[9] == 't'$mode += 01001;
      else if (
$permissions[9] == 'T'$mode += 01000;

      
printf('Mode is %d decimal and %o octal'$mode$mode);
?>

zual__ at gogo dot mn (2007-10-31 04:53:46)

greate ftp newfolder=dir;
chmod --dir change 777;

<?php
$ftp_server
='server';
$conn_id ftp_connect("$ftp_server");
ftp_login($conn_iduserpassword);
ftp_mkdir($conn_iddir/dir);
ftp_site($conn_id'CHMOD 777, dir/dir');
ftp_close($conn_id);
?>

til_roque at yahoo dot com (2007-10-10 20:03:00)

Problem:
you are trying to circumvent SAFE_MODE setting that prevents you from using chmod() on files you uploaded via a regular ftp client, because php may run as user 'nobody', which is not the user from your ftp session.
using ini_set() won't work
using ftp_chmod() won't work either
Solution:
copy file to some temorary directory.
delete original file altogether.
copy temporary file back to original location.
do the chmod()

mmj048 at gmail dot com (2007-10-04 20:56:16)

If you want to use a string for the second parameter, including user input, you MUST use octdec.
http://www.php.net/octdec

martin at aarhof dot eu (2007-08-17 07:15:14)

Just for those peoples can't remeber the codes 777 and so on I just created a small class :-)

<?php

class Chmod
{
    
    private 
$dir;
    private 
$modes = array('owner' => 'group' => 'public' => 0);
    
    public function 
setOwnermodes($read,$write,$execute) {
        
$this->modes['owner'] = $this->setMode($read,$write,$execute);
    }
    
    public function 
setGroupmodes($read,$write,$execute) {
        
$this->modes['group'] = $this->setMode($read,$write,$execute);
    }

    public function 
setPublicmodes($read,$write,$execute) {
        
$this->modes['public'] = $this->setMode($read,$write,$execute);
    }
    
    public function 
getMode() {
        return 
$this->modes['owner'] . $this->modes['group'] . $this->modes['public'];
    }
    
    private function 
setMode($r,$w,$e) {
        
$mode 0;
        if(
$r$mode+=4;
        if(
$w$mode+=2;
        if(
$e$mode+=1;
        return 
$mode;
    }

    
}

$test = new Chmod;
$test->setOwnermodes(true,true,true);
$test->setGroupmodes(true,true,true);
$test->setPublicmodes(true,true,true);
chmod($dir $test->getMode());
// chmods $dir to 0777
?>

Ambriel_Angel at www dot ambriels dot net/entry (2007-03-25 06:00:09)

<?php
error_reporting
(E_ERROR E_PARSE);
/* Makes is so Directories are not browseable to the public,
removing only the Public = Read permission, while leaving 
the other chmod permissions for the file in tact.

If you have exectue already on, and read off, public viewers will only
be able to view files through links, but not browse
around to see what's inside of directories and see what
you've got laying around. */
//-------------------------------------------------------
// Get file mode
// Get file permissions supported by chmod
function getmod($filename) {
   
$val 0;
   
$perms fileperms($filename);
   
// Owner; User
   
$val += (($perms 0x0100) ? 0x0100 0x0000); //Read
   
$val += (($perms 0x0080) ? 0x0080 0x0000); //Write
   
$val += (($perms 0x0040) ? 0x0040 0x0000); //Execute
 
   // Group
   
$val += (($perms 0x0020) ? 0x0020 0x0000); //Read
   
$val += (($perms 0x0010) ? 0x0010 0x0000); //Write
   
$val += (($perms 0x0008) ? 0x0008 0x0000); //Execute
 
   // Global; World
   
$val += (($perms 0x0004) ? 0x0004 0x0000); //Read
   
$val += (($perms 0x0002) ? 0x0002 0x0000); //Write
   
$val += (($perms 0x0001) ? 0x0001 0x0000); //Execute

   // Misc
   
$val += (($perms 0x40000) ? 0x40000 0x0000); //temporary file (01000000)
   
$val += (($perms 0x80000) ? 0x80000 0x0000); //compressed file (02000000)
   
$val += (($perms 0x100000) ? 0x100000 0x0000); //sparse file (04000000)
   
$val += (($perms 0x0800) ? 0x0800 0x0000); //Hidden file (setuid bit) (04000)
   
$val += (($perms 0x0400) ? 0x0400 0x0000); //System file (setgid bit) (02000)
   
$val += (($perms 0x0200) ? 0x0200 0x0000); //Archive bit (sticky bit) (01000)

   
return $val;
}

//-------------------------------------------------------
// Find out if file has mode
function hasmod($perms$permission) {

# User Read = 0400 (256), Write = 0200 (128), Execute = 0100 (64)
# Group Read = 0040 (32), Write = 0020 (16), Execute = 0010 (8)
# Public Read = 0004 (4), Write = 0002 (2), Execute = 0001 (1)

    
return (($perms $permission) == $permission);
}

//-------------------------------------------------------
// Take the read option off of all the subdirectories of the included path
function pathlock($dir$listall false$testrun true) {
   echo 
"START @ " date("F j, Y, h:i:s A") . "<br><br>";
   echo (
$testrun '**Test Run Activated (no changes will be made).**<br><br>' '**Live Run Activated.**<br><br>');
   echo 
$dir " is our directory.<br><br>\n";
   echo 
"[...IN PROGRESS...]<br><br>";

   
$file_list '';
   
$stack[] = $dir;
  
   while (
$stack) {
      
$current_dir array_pop($stack);
      if (
$dh opendir($current_dir)) {
          while ((
$file readdir($dh)) !== false) {
              if (
$file !== '.' AND $file !== '..') {
                  
$current_file "{$current_dir}/{$file}";
               if (
is_dir($current_file)) {
                      
// BEG ADD PATH    
                   
$mode getmod($current_file);    //Get the mode
                      
$HasPubRead hasmod($mode,4);
                   if (
$HasPubRead || $listall) {    // Can the public read this dir?
                  //======================================
                    
$ch true;
                  
$take 0;
                       
// Change the mode:
                     
if ($HasPubRead) {
                          
$take 4;         // Value for Public Read. 4 is the same in octal and decimal.
                          
if (!$testrun) {
                              
$ch chmod($current_file$mode-$take); 
                          }
                      } 

                    echo 
$current_file ",current=" decoct($mode) . 
                        ((
$mode!==$mode-$take) ? ",new=" decoct($mode-$take) : '') .
                        (
$ch '' ',FAILED') . "<br>\n";
                   } 
// end if hasmod
                   // END ADD PATH                           
                      
$stack[] = $current_file;
                  } 
// if if_dir
              
//if ($file !== '.' AND $file !== '..')
          
//while (($file = readdir($dh)) !== false)
      
//if ($dh = opendir($current_dir))
// while ($stack)

    
echo "<br>COMPLETE @ " date("F j, Y, h:i:s A") . "<br>\n";
return;
   
//return $path_list;
// end function

//-------------------------------------------------------
    //listall Show all folders, even one's we're not going to process?
    //testrun Do a test run without making any changes
    
pathlock($_SERVER["DOCUMENT_ROOT"],false,true); // listall?=false, testrun?=true

?>

redeyeleader (2007-02-10 08:05:01)

Here's a version that works with PHP 5.x - I use this to watermark images on a shared server. 

<?php
// Connect to the FTP to chmod the file via FTP

$ftpUserName 'username';
$ftpUserPass 'userpass';
$ftpServer 'ftp.example.com';

  
$ftpConn ftp_connect($ftpServer);
  
  if (!
$ftpConn) {
    die(
"Unable to connect to $ftpServer");
  }

if (@
ftp_login($conn_id$ftpUserName$ftpUserPass)) {
   echo 
"Connected as $ftpUserName @ $ftpServer";

else {
   echo 
"Couldn't connect as $ftpUserName";
   
ftp_close($ftpConn);
   die(
"Closed connection to $ftpServer");
}

//Now change permissions to 666 or whatever you need 

echo ftp_chmod($ftpConn0666$ftpFilename) ? "CHMOD successful!" 'Error';

// do what you need here

//Now change permissions back to 644 or whatever 
echo ftp_chmod($ftpConn0644$ftpFilename) ? "CHMOD successful!" 'Error';

// Close the connection
ftp_close($conn_id);
?>

hodgman at ali dot com dot au (2007-01-17 21:06:16)

My PHP script refused to delete read-only files (which is probably a good thing), but I couldnt find out how to fix this on windows.

The solution is simple, i just replaced 
<?php @unlink$entry ); ?>
with:
<?php 
                
@chmod$entry0777 );
                @
unlink$entry );
?>

chmod isnt supposed to work on windows, but 0777 seems to clear the read only flag, and 0444 seems to set the read only flag.

info at web-in-time dot eu (2007-01-04 13:11:44)

As you might have noticed there is a minor bug in webmaster at danopia dot 5gigs dot com's code:
You have to set $ftp_root variable outside the function chmod_open() and have to set it as global within the chmod_file() function.
With these patches the code really works fine. THX!
Ben

webmaster at danopia dot 5gigs dot com (2007-01-02 18:20:27)

Thanks for your code, "imoldgreg at o2 dot co dot uk". I am using it for an instalation script that has to CHMOD a bunch of files. I have found it faster to use the same connectino for each, as shown below.

<?php

// Thanks to "imoldgreg at o2 dot co dot uk" for the base 'CHMOD via FTP' script.

function chmod_open()
{
    
// Use your own FTP info
    
$ftp_user_name 'chmod@XXXXXXXXX.com';
    
$ftp_user_pass 'XXXXXXXXXX';
    
$ftp_root '/';
    
$ftp_server 'localhost';
    
$conn_id ftp_connect($ftp_server);
    
$login_result ftp_login($conn_id$ftp_user_name$ftp_user_pass);
    return 
$conn_id;
}

function 
chmod_file($conn_id$permissions$path)
{
    if (
ftp_site($conn_id'CHMOD ' $permissions ' ' $ftp_root $path) !== false)
    {
        return 
TRUE;
    }
    else
    {
        return 
FALSE;
    }
}

function 
chmod_close($conn_id)
{
    
ftp_close($conn_id);
}

// CHMOD the required setup files

// Connect to the FTP
$conn_id chmod_open();

// CHMOD each file and echo the results
echo chmod_file($conn_id777'master/cache/') ? 'CHMODed successfully!' 'Error';
echo 
chmod_file($conn_id777'master/files/') ? 'CHMODed successfully!' 'Error';
echo 
chmod_file($conn_id777'master/store/') ? 'CHMODed successfully!' 'Error';
echo 
chmod_file($conn_id766'master/config.php') ? 'CHMODed successfully!' 'Error';
echo 
chmod_file($conn_id777'master/images/avatars/upload/') ? 'CHMODed successfully!' 'Error';

// Close the connection
chmod_close($conn_id);

?>

Here, the same FTP connection is used for each CHMOD command, making the execute time lower. This is essential for me, since my script is also copying a bunch of files.

imoldgreg at o2 dot co dot uk (2006-11-30 17:32:33)

an update to 'neil at 11 out of 10's code for changing mode using FTP.

changes: proper array added within the function (better for those of us who only need to connect to one ftp server) so only the mode and directory name need to be passed.

the octal added, for completeness and predictable stability.

<?php
function changemode($xcite)
{
$ftp_details = array(
ftp_user_name => 'username'
ftp_user_pass => 'password'
ftp_user_root => '/public_html/'
ftp_server => 'ftp.something.org' 
);

$path "public";
$mod intval($xcite8);

   
// extract ftp details (array keys as variable names)
   
extract ($ftp_details);
   
   
// set up basic connection
   
$conn_id ftp_connect($ftp_server);
   
   
// login with username and password
   
$login_result ftp_login($conn_id$ftp_user_name$ftp_user_pass);
   
   
// try to chmod $path directory
   
if (ftp_site($conn_id'CHMOD '.$mod.' '.$ftp_root.$path) !== false) {
       
$success=TRUE;
   } 
   else {
       
$success=FALSE;
   }

   
// close the connection
   
ftp_close($conn_id);
    return 
$success;
}

?>

for those of you, like me, who were looking for a way to make an 'un-hackable' uploader, here's the closest i got, now for a field test, good luck!

NeoSmart Technologies (2006-07-25 03:08:59)

The program mentioned below (CHMOD-Win) has been rewritten since, and CHMOD-Win version 3.0 is available for download at http://neosmart.net/dl.php?id=4
It is a conversion utility for CHMOD on Windows and ACL on Linux, comes in handy for installing commercial scripts or defining security policies.

neil at 11 out of 10 (2006-04-11 12:20:42)

If you get a warning like chmod(): Operation not permitted in /home/folder/public_html/admin/includefiles/fileupload.php on line 24

You can use the ftp_site() function to send a CHMOD command through.
<?php

$ftp_details
['ftp_user_name'] = $row['username'];
$ftp_details['ftp_user_pass'] = $row['password'];
$ftp_details['ftp_root'] = '/public_html/';
$ftp_details['ftp_server'] = 'ftp'.$_SERVER['HTTP_HOST'];

function 
chmod_11oo10($path$mod$ftp_details)
{
    
// extract ftp details (array keys as variable names)
    
extract ($ftp_details);
    
    
// set up basic connection
    
$conn_id ftp_connect($ftp_server);
    
    
// login with username and password
    
$login_result ftp_login($conn_id$ftp_user_name$ftp_user_pass);
    
    
// try to chmod $path directory
    
if (ftp_site($conn_id'CHMOD '.$mod.' '.$ftp_root.$path) !== false) {
        
$success=TRUE;
    } 
    else {
        
$success=FALSE;
    }

    
// close the connection
    
ftp_close($conn_id);
    return 
$success;
}
?>
The key thing to remember is that the document root and the ftp root are not the same.
e.g. document root may be "/home/folder/public_html/"
but the ftp root might be "/public_html/"

Hope this helps someone.  You might need this solution if you are on a shared server.

memp (2005-08-22 15:04:11)

If you are storing your mode in a variable like
$mode = 0755;
you will run into the inevitable octal mode problem. An easy way around that is to use the octdec() function.
chmod("some_filename.ext", octdec($mode));

masha at mail dot ru (2005-07-10 21:23:49)

Usefull reference:
Value Permission Level
400 Owner Read
200 Owner Write
100 Owner Execute
40 Group Read
20 Group Write
10 Group Execute
4 Global Read
2 Global Write
1 Global Execute
(taken from http://www.onlamp.com/pub/a/php/2003/02/06/php_foundations.html)

alex at feidesign dot com (2005-04-01 04:20:47)

If you cannot chmod files/directories with PHP because of safe_mode restrictions, but you can use FTP to chmod them, simply use PHP's FTP-functions (eg. ftp_chmod or ftp_site) instead. Not as efficient, but works.

haasje at welmers dot net (2004-11-27 12:09:09)

For recursive chmod'ing see the function below.
Only really usefull when chmod'ing a tree containing directories only, jet, since you don't want an executable bit on a regular file. Who completes the function so it's accepting strings like "g+w", and it's as usefull as unix "chmod -R" ? ;-)

<?php

function chmod_R($path$filemode) { 
    if (!
is_dir($path))
       return 
chmod($path$filemode);

    
$dh opendir($path);
    while (
$file readdir($dh)) {
        if(
$file != '.' && $file != '..') {
            
$fullpath $path.'/'.$file;
            if(!
is_dir($fullpath)) {
              if (!
chmod($fullpath$filemode))
                 return 
FALSE;
            } else {
              if (!
chmod_R($fullpath$filemode))
                 return 
FALSE;
            }
        }
    }
 
    
closedir($dh);
    
    if(
chmod($path$filemode))
      return 
TRUE;
    else 
      return 
FALSE;

?>

PerfectWeb (2004-11-22 19:58:50)

As noted by others below... 1) you cannot pass a string to chmod() as the mode, and 2) decimals work as well as octals for the mode.

If you need to come up with the mode on the fly (maybe based on user input) and want to use something like:

$mode = '0'.$owner.$group.$public;

you can use your $mode (which is a string) with chmod like this:

<?php
 
// octal mode in a string i.e. '0755'
 
$mode '0'.$owner.$group.$public;

 
$mode_dec octdec($mode);    // convert octal mode to decimal
 
chmod($filename$mode_dec);
?>

fernando at gym-group dot com (2004-11-12 07:10:16)

Oliver Hankeln (2004-07-01 08:21:41)

Well, you don't need octals.
You need a value that can easily computed and remembered if printed in octal.
511 (decimal) is the same as 777 (octal).
So it's the same wether you write
chmod("foo",511)
or
chmod("foo",0777)
The latter is just better readable.

raven_25041980 at yahoo dot com (2004-05-24 10:45:42)

If you have a mode as a string, chmod will insanely mess up your permissions. Instead of using 

<?php 

@chmod($file_or_dir_name$mode);

?>

use 

<?php 

@chmod(file_or_dir_nameintval($mode8));

?>

where 8 -> the base to convert into. You need octals, baby, for chmod...

More on intval here: http://www.php.net/manual/en/function.intval.php

agrenier at assertex dot com (2004-04-02 05:17:34)

If you find that chmod does not work on your file and that a new file cannot be created, first try to chmod the directory where the file is being created to 0666/0777. Then PHP should be able to write/append files with mode 0644.

agrenier at assertex dot com (2004-04-02 05:11:09)

This function will chmod a $filename before writing to it if:

1 - It exists
2 - It is not writeable
3 - PHP has permission to chmod files

If PHP can't chmod, then the script will end. Otherwise it will attempt to write to a new file.

<?php

    
function file_write($filename$flag, &$content) { 
        if (
file_exists($filename)) {
            if (!
is_writable($filename)) {
                if (!
chmod($filename0666)) {
                     echo 
"Cannot change the mode of file ($filename)";
                     exit;
                };
            }
        }
        if (!
$fp = @fopen($filename$flag)) {
            echo 
"Cannot open file ($filename)";
            exit;
        }
        if (
fwrite($fp$content) === FALSE) {
            echo 
"Cannot write to file ($filename)";
            exit;
        } 
        if (!
fclose($fp)) {
            echo 
"Cannot close file ($filename)";
            exit;
        }
    }

?>

Jazeps Basko (2004-01-27 07:37:07)

To convert 'rwxr-xr--' to a number representation of chmod, i use this:
<?php
    
function chmodnum($mode) {
        
$mode str_pad($mode,9,'-');
        
$trans = array('-'=>'0','r'=>'4','w'=>'2','x'=>'1');
        
$mode strtr($mode,$trans);
        
$newmode '';
        
$newmode .= $mode[0]+$mode[1]+$mode[2];
        
$newmode .= $mode[3]+$mode[4]+$mode[5];
        
$newmode .= $mode[6]+$mode[7]+$mode[8];
        return 
$newmode;
    }
?>

pmichaud at pobox dot com (2003-04-19 15:45:42)

In the previous post, stickybit avenger writes:
    Just a little hint. I was once adwised to set the 'sticky bit', i.e. use 1777 as chmod-value...

Note that in order to set the sticky bit on a file one must use '01777' (oct) and not '1777' (dec) as the parameter to chmod:

<?php
    chmod
("file",01777);   // correct
     
chmod("file",1777);    // incorrect, same as chmod("file",01023), causing no owner permissions!
?>

Rule of thumb: always prefix octal mode values with a zero.

sticky bit avenger (2003-03-12 03:30:44)

Just a little hint. I was once adwised to set the 'sticky bit', i.e. use 1777 as chmod-value. Do NOT do this if you don't have root privileges. When 'sticky bit' is set ONLY the fileuser can delete it afterwards, typically 'httpd' or something like that in case of an upload-script for example. I was unaware of this and actually had to make a script for deleting these files as I could not do this from ftp/ssh even though I did have read/write/execute access to both files and folders. Use simply '0777' or similiar.

Half-Dead at nospam dot com (2002-11-08 02:42:59)

[Editor's note:
That is due the fact Win32 systems treat premissions. You do not really have any other levels but read-only.
Maxim]
On WinME with apache chmod also works to a certain limit.
What happens is that apparently only the first number is counted, so 0666 (read-write) is the same as 0777, 0644, 0600, etc, and 0444 (read-only) is the same as 477, 400, etc.
..didn't test 0500 series

jon at zend dot com (2001-10-15 08:37:34)

if 'mode' is held in a variable and is and octal value you need to convert it to decimal before passing it to the function:
chmod ($filename, octdec($mode))

gnettles2 at home dot com (2001-08-24 11:20:10)

Usually when you're trying to write to af file, you'll need to chmod the file to something like 666 or 755. You can use a command to chmod the file for you, which is especially useful when you're making a script where you're setting it up so that your users don't have to peform a bunch of actions to setup the script. When i wrote my news program script, I only had two files. install.php and config.php. All you had to do was chmod install.php to 666 and open it up in a web browser and answer a few questions. The script itself setup the rest of the files and chmodded them for you.

易百教程