Write permissions on uploaded files — Linux, Apache, PHP
I am working on a PHP script that transfers files using FTP functions. It has always worked on my production server (which is a hosting service). The development server I have just setup (I am a novice to servers) is Debian Lenny with Apache2, PHP5, and MySQL5. The file transfer works correctly, but once the file has been written to the server, it has permissions of 600. This makes it impossible for me to view the file (JPEG) in the web browser, as permission is denied. I have scoured the internet and even broken my server installation and reinstalled it trying to figure this out (which has been fun, nonetheless!). I know it is unwise to set 777 permissions on public accessible files, but even that will not solve the problem. The only thing that works is if I chmod 777 thefile.jpg after it has been transferred, which is not a working solution. I tried changing the owner of my site files to www-data per this post, but that also does not work. My user is mike , and it still does not work whether the owner of the files is mike or root . Would somebody point me in the right direction? Thanks! And, of course, let me know if I can clarify anything.
3 Answers 3
this is more related to your ftp server configuration, and not so much to apache. which server are you using for ftp? i believe vsftpd is the default ftp server for Debian Lenny, the options you might need to look at in your vsftpd.conf file are: chown_upload_mode and file_open_mode
the default for chown_upload_mode is 0600 which makes me think that might be what you need to set, and then restart your FTPd and try again.
Ahhh that makes sense! Yes, I installed vsftpd so that I could transfer files from my workstation to the server. I’m looking at it now.
Do you think it would be a good idea to try and use the same FTP application that my hosting service uses?
you will want to set chown_upload_mode and file_open_mode to 644 which allows read/write to the owner, read to group, and read to world. permissions work like this: 1 = execute, 2 = write, 4 = read. 7 = read/write/execute, and so on.
i don’t know, but whatever you use to send files to your web server, you’ll need to look at the umask and permissions options in the configuration. also, most FTP clients will allow you to set permissions on files you have uploaded, so check the settings of your ftp client as well.
I ended up having internet connection difficulties with Debian and finally reinstalled Ubuntu 10.04 Server Edition. The internet problem was resolved. I started everything over and ended up only uncommenting write_enable=YES and local_umask=022 in /etc/vsftpd.conf . This allows my PHP FTP script to transfer files with permissions of 0644 . This allows my other scripts to actually be able to read the images for displaying them in the browser. Thank-you for pointing me towards vsftpd.conf , as that was the solution.
Php ftp file permissions
For those who dont want to deal with handling the connection once created, here is a simple class that allows you to call any ftp function as if it were an extended method. It automatically puts the ftp connection into the first argument slot (as all ftp functions require).
public function __construct ( $url ) <
$this -> conn = ftp_connect ( $url );
>
public function __call ( $func , $a ) <
if( strstr ( $func , ‘ftp_’ ) !== false && function_exists ( $func )) <
array_unshift ( $a , $this -> conn );
return call_user_func_array ( $func , $a );
>else <
// replace with your own error handler.
die( » $func is not a valid FTP function» );
>
>
>
// Example
$ftp = new ftp ( ‘ftp.example.com’ );
$ftp -> ftp_login ( ‘username’ , ‘password’ );
var_dump ( $ftp -> ftp_nlist ());
?>
Upload file to server via ftp.
$ftp_server = «» ;
$ftp_user_name = «» ;
$ftp_user_pass = «» ;
$file = «» ; //tobe uploaded
$remote_file = «» ;
// 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 );
// upload a file
if ( ftp_put ( $conn_id , $remote_file , $file , FTP_ASCII )) <
echo «successfully uploaded $file \n» ;
exit;
> else <
echo «There was a problem while uploading $file \n» ;
exit;
>
// close the connection
ftp_close ( $conn_id );
?>
In example 2 above you may need to set the system to to use pasv to get a result ie:
$ftp = new ftp(‘ftp.example.com’);
$ftp->ftp_login(‘username’,’password’);
$ftp->ftp_pasv(TRUE);
var_dump($ftp->ftp_nlist());
syntax error in the above example, ftp_nlist requires a directory parameter:
$ftp->ftp_nlist(‘.’); // retrieve contents of current directory
ftp_chmod
Sets the permissions on the specified remote file to permissions .
Parameters
The new permissions, given as an octal value.
Return Values
Returns the new file permissions on success or false on error.
Changelog
Examples
Example #1 ftp_chmod() example
// set up basic connection
$ftp = ftp_connect ( $ftp_server );
// login with username and password
$login_result = ftp_login ( $ftp , $ftp_user_name , $ftp_user_pass );
// try to chmod $file to 644
if ( ftp_chmod ( $ftp , 0644 , $file ) !== false ) echo » $file chmoded successfully to 644\n» ;
> else echo «could not chmod $file \n» ;
>
// close the connection
ftp_close ( $ftp );
?>
See Also
User Contributed Notes 7 notes
Using the excellent octdec and decoct functions you can make this easy:
$mode = «644» ;
$mode = octdec ( str_pad ( $mode , 4 , ‘0’ , STR_PAD_LEFT ) );
ftp_chmod ( $ftp_stream , $mode , $file );
?>
Just wanted to contribute a quick note for those who are still experiencing issues with changing the permissions via FTP.
If you are having trouble with PHP recognizing the mode as an integer, you can take the previous poster’s method:
$mode = octdec ( str_pad ( $mode, 4, ‘0’, STR_PAD_LEFT ) );
And add the following snippet right after:
This will force PHP to recognize the mode as an integer when you do:
ftp_chmod ( $conn_id, $mode, $path );
These together never seem to fail for me.
It took me a while to figure out how to use this function in my situation because I needed the $mode to be passed to this function as a variable that was read from a database. Since the database returns the value as an integer without a leading zero, I could not get the operation to work because adding a leading zero in PHP turns the value into a string.
For example, this does not work in my situation:
// Assume that this is the value returned from the database.
$mode = 644 ;
// Now try to chmod using this value.
ftp_chmod ( $conn_id , $mode , ‘test.txt’ );
// The file now has permissions of 204 and not 644
?>
Adding a leading zero doesn’t work either:
// Assume that this is the value returned from the database.
$mode = 644 ;
// Now try to chmod using this value.
ftp_chmod ( $conn_id , ‘0’ . $mode , ‘test.txt’ );
// The file now has permissions of 204 and not 644
?>
I tried many ways to get it to work even converting it from oct to dec using octdec and then back to decoct and nothing worked. This is the only way I was able to get it to work, with an eval statement.
// Assume that this is the value returned from the database.
$mode = 644 ;
// Turn the mode into a string
$np = ‘0’ . $mode ;
// Now run chmod with the eval’d string parsed as an integer.
ftp_chmod ( $conn_id , eval( «return( < $np >);» ), ‘test.txt’ );
// The file now has permissions of 644
?>
Of course, you will have to make sure that the value of $mode only contains 3 digits. Always do checking on your values before handing it off to eval().
The «mode» parameter of the PHP5 ftp_chmod function is an integer value that is supposed to be given as an octal number, like the argument for the «chmod» command line tool.
Thus the sprintf must use the %o formatting character, so that the passed integer value is really represented as an octal number to the CHMOD site command for the FTP server.
So, IMHO, rabin’s version is correct (it definitely worked for me).
Ok,
so if 2 people say that my way is wrong and the other is right, i will take mine back.
I posted it cause for me just the way i used it worked (i don’t know why)
AND: i would not say something like: «I would try before post», in my opinion that is realy unfriendly, cause i tryed!
As mentioned in the note below, the function posted by «hardy add mapscene dot com» works incorrectly if used with an octal mode, the way the php5 function is used.
This function works exactly like the the php5 one:
if (! function_exists ( ‘ftp_chmod’ )) function ftp_chmod ( $ftp_stream , $mode , $filename )
return ftp_site ( $ftp_stream , sprintf ( ‘CHMOD %o %s’ , $mode , $filename ));
>
>
?>
rabin’s code works just fine as a replacement for ftp_chmod().
I would try that before trying cspiegl’s solution for pre-php 5 installations.