How to debug move_uploaded_file() in PHP - php

move_uploaded_file() won't work for me anymore, it was working fine and just stopped out of nowhere. Is there a way for me to check why it's not working anymore? Here's what I currently have, but it only returns TRUE or FALSE.
$status = move_uploaded_file($tempFile, $targetFile);
if($status) {
echo 'its good';
} else {
echo 'it failed';
}
I know the path is 100% correct and the directory is CHMOD 755. Is there anything I might be doing wrong?

Maybe this will work:
if(!move_uploaded_file($_FILES['attachement']['tmp_name'], $uploadfile)) {
echo 'Your file was not uploaded please try again
here are your debug informations:
'.print_r($_FILES);
} else {
echo 'image succesfully uploaded!';
}

Check your error reporting level (see error_reporting function). You should get a warning or notice that's a bit more descriptive.
Also, check that the user your PHP script runs as (usually the server's user, which is nobody or www-data on a lot of systems, but YMMV) owns the directory. With 755, only the owner of the directory can write to it.

Permissions of 755 means that only the owner of the directory can write to that directory.
So the question is, who is the owner and as what user is the web-server / php running?
If they donĀ“t match, you can either change the ownership or the group (also changing the permissions to 775).

Related

PHP is_writable false for NFS folder although files can be written

Sorry, I'm not sure, if this is the correct forum because I don't know the cause for the issue, I'm facing.
I installed NextCloud on a Raspbian (Stretch 9) and moved the data directory to a mounted NFS folder. When I try to access NextCloud, I got the error message 'Data directory is not writable'.
So I dug a better deeper and could finally isolate the issue to the interaction between PHP7.0 and the NFS:
For some reason, the application can write to the directory but is_writable returns false.
I have created the following PHP script:
<?php
$dirname = '/var/churros/data/nextcloud/';
//$dirname = '/tmp/';
$myfile = fopen($dirname.'newfile.txt', "w") or die("Unable to open file!");
$txt = "John Doe\n";
fwrite($myfile, $txt);
fclose($myfile);
echo nl2br("File ".$dirname."newfile.txt written\n");
if (touch($dirname.'/chkpt.tmp')) {
echo nl2br("touch(".$dirname."/chkpt.tmp) successful\n");
} else {
echo nl2br("touch(".$dirname."/chkpt.tmp) failed\n");
}
if (is_writable($dirname)) {
echo 'Directory '.$dirname.' is writable';
} else {
echo 'Directory '.$dirname.' is not writable';
}
phpinfo();
?>
The result is that
newfile.txt is created in the data directory with the given text (John Doe)
Touch succeeded, i.e. the checkpoint file is created
is_writable returns false Screenshot of 'debug.php' with NFS directory
When I change to directory to a local directory like \tmp everything is fine Screenshot of 'debug.php' with /tmp directory
My NFS is mounted as
192.168.1.100:/volume1/pidata/donut on /var/churros type nfs4 (rw,relatime,vers=4.0,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.103,local_lock=none,addr=192.168.1.100)
and obviously the user mapping and access rights are correct:
namei -l /var/churros/web/nextcloud/
f: /var/churros/web/nextcloud/
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root churros
drwxr-xr-x www-data www-data web
drwxrwxr-x www-data www-data nextcloud
On the command line, as user www-data, I can access the directory and write to it as well.
Finally, SELinux is not installed/enabled on the box.
So: Any idea why PHP is_writable fails on the NFS directory or how I can debug this PHP function?
The issue could be the unix user id is different for user "www-data" for the 2 different systems.
In detail, from the php src, you can see that:
is_writable() is defined at ext/standard/php_filestat.h, which uses:
php_stat header file defined at php_stat()
VCWD_ACCESS() function is used
In turn:
VCWD_ACCESS()
is a convenience wrapper for virtual_access()
virtual_access()
is thread safe wrapper around the access() function that takes
per-thread virtual working directories into account.
Finally, looking access() doc:
The access() function checks the file named by the pathname pointed to by the path argument for accessibility according to the bit pattern contained in amode, using the real user ID in place of the effective user ID and the real group ID in place of the effective group ID.
and also at the access() linux documentation, it states:
access() may not work correctly on NFS file systems with UID mapping enabled, because UID mapping is done on the server and hidden from the client, which checks permissions. Similar problems can occur to FUSE mounts.
Try:
var_dump(stat('nfs-filename'));
and see which uid you get.
Reference:
Similar issue with php session in nfs
Most likely this is is_writable() function's bug.
You may fix this NextCloud issue:
} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
//common hint for all file permissions error messages
$permissionsHint = $l->t('Permissions can usually be fixed by giving the webserver write access to the root directory. See %s.',
[$urlGenerator->linkToDocs('admin-dir_permissions')]);
$errors[] = [
'error' => 'Your data directory is not writable',
'hint' => $permissionsHint
];
AND
/usr/share/webapps/nextcloud/lib/private/Console/Application.php
if ($input->getFirstArgument() !== 'check') {
$errors = \OC_Util::checkServer(\OC::$server->getSystemConfig());
if (!empty($errors)) {
foreach ($errors as $error) {
$output->writeln((string)$error['error']);
$output->writeln((string)$error['hint']);
$output->writeln('');
}
throw new \Exception("Environment not properly prepared.");
}
}
Source #1, Source #2

php chmod() not changing permissions

I am having problems with a picture uploading script.
I know there are hundreds of the same questions, but I haven't found the one that would be work for me.
$upload_dir = "images/postcards/";
chmod($upload_dir, 777);
if (is_writable($upload_dir)) {
echo 'The file is writable';
} else {
echo 'The file is not writable';
}
This always returns that the file is "not writable"
I tried setting chmod to 0777 and -rwxrwxrwx. But result was always the same. Any Ideas?
The directory must be owned by the user invoking the script (typically www-data, apache or httpd if you're running the script in a apache/*NIX setup). A user can't set 777 permissions on directories it doesn't own.
See the note on the chmod() manual:
The current user is the user under which PHP runs. It is probably not
the same user you use for normal shell or FTP access. The mode can be
changed only by user who owns the file on most systems.
First , open PHP error_report by adding two line on top of your code, see if there is a error coming from chmod:
ini_set('display_errors', true);
error_reporting(E_ALL);
Make sure your WebServer has the permission to that directory, my guess is the WebServer don't have permission.
I was having similar troubles using chmod, although the file was owned by apache:apache (webserver user). In my case SELinux was getting in the way, disabling it made this clear:
sudo setenforce 0
And the chmod works. Now on to figuring out how to make a SELinux exception for this case...
(and don't forget to enable SELinux, of course)
I already had the same problem you can change the file's permission by this code :
<?php
$ftp_details['ftp_user_name'] = 'your ftp username';
$ftp_details['ftp_user_pass'] = 'your ftp password';
$ftp_details['ftp_root'] = '/public_html/';
$ftp_details['ftp_server'] = 'ftp' . $_SERVER['HTTP_HOST'];
function ftp_chmod($path, $mod, $ftp_details) {
extract($ftp_details);
$conn_id = ftp_connect($ftp_server);
$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;
}
ftp_close($conn_id);
return $success;
}
?>
I didn't run this code but I think it's Ok and it will help you.
tell me if your problems resolved.

PHP file doesn't rewrite

I make a site map, and make it with php file, that generate it from mysql. I change host and now I have problem with writing into file. I can't understand something.
Here is my example:
<?php
$xml = 'bla bla xml'; //... some xml generating code
$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/my_site_map.xml', 'w');
if($fp)
echo 'we opened it';
else
echo 'we failed';
$fwrite=fwrite($fp, $xml, strlen($xml));
if($fwrite==false)
echo "another fail";
fclose($fp);
echo "we done";
?>
The question is: my file my_site_map.xml have a permission 664 (rw-rw-r--), and I can't use this script if I open this php page from browser, so, if I try to do this I'll see: "we failed another fail we done"; But if I open this through crontab and see a log file, I can see this: "we opened it we done". I want exactly this but the main problem is that the file isn't have been rewritten. Why? And how can I fix this? Thanks.
My server is nginx not an Apache, didn't thought that this info will valuable
Well I don't have enough rep to comment so this will have to be an answer.
I'm going to take a stab in the dark and say the file is owned by your user or root, not the process that is running the webserver. Nor is the file owned by the group the webserver process is run under.
So either chown/chgrp the file to be owned by the apache(?!) process running, e.g. chown apache file or set the file to have write permissions to everyone, e.g. chmod 666 file
Don't chmod 777 as commented above unless it's an executable file and you want anyone to be able to run it. The 1st solution is a better practice than just giving anyone read access to a file.
Edit: In comment to the comments on the original answer above, if the file isn't an executable then don't give it 7 for any permisions. 6 is read/write and is suitable for a text file you are opening to write to (even 2 is if it comes to that).
Edit 2: Try catching any exceptions that your fopen function runs in a try catch block:
try {
$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/my_site_map.xml', 'w');
} catch (Exception $e) {
echo "The error is" . $e->getMessage();
}
For PHP code here are the links to change it on the fly. You can change it to what ever make your edits then change it back as needed.
http://php.net/manual/en/function.chmod.php
http://php.net/manual/en/function.chown.php
http://php.net/manual/en/function.chgrp.php
Examples are included on each link with the documentations. Find the permissions that works best for what your doing. There isn't a one size fits all for permissions since it really depends on your end product (web app, page, what ever).

php unlink. returns no error message and doesn't delete my file

I'm simply trying to delete a file using PHP's unlink. I found an answer on here that told me the best way to do this and I implemented it. Heres the code I am using.
$log_path = realpath($log_file);
if (is_readable($log_path)){
print file_exists($log_path);
$deleted = unlink($log_path);
print "Deleted:".$deleted;
print "Exists:".file_exists($log_path);
}
This just prints 1Deleted:exists:1. I also tried to add in print_r(error_get_last()); under the unlink, but this also returned nothing. All files in the directory are chmod 777 * and there are no other file handlers open. ....what the heck...
The code you used is needlessly cumbersome. A simple call to unlink should do the trick:
unlink( $log_file );
But let's find out what is going wrong. The file exists, because you enter the loop where the print statements are done. The unlink call probably returns false, because the output is "11" and not "111".
So my gut says, it must be a file permissions issue. Are you sure the web user has permission to remove the file? Can you show us the folder permissions, for instance by running ls -la on the command line and pasting the output?
unlink returns either true or false. If you try to print false (print $deleted;), this will print an empty string.
Try this instead:
print $deleted ? "The file was deleted" : "The file was not deleted";
I think you need to check if $log_path is file. Use:
if( is_file( $log_path ) AND is_readable( $log_path ) )
Also, add next line to begin of your script to show all errors and warnings:
ini_set( 'error_reporting', E_ALL );
Its not that your files need to be 0777. It also necessary that your directory can be accessed. What's the mod of your directory?
Next: print $deleted; apparently print false, which is shown as nothing. Try this: echo $deleted ? 1 : 0;
I don't really know the problem, but you should check, if the file is writable and not if it is readable:
<?php
$log_file = "/tmp/test.log";
$log_path = realpath($log_file);
echo "Testing: ". $log_path."\n";
if (is_writable($log_path)) {
echo "exists? ";
echo (file_exists($log_path))?"yes\n":"no\n";
$deleted = unlink($log_path);
echo "deleted? ";
echo ($deleted)?"yes\n":"no\n";
echo "exists? ";
echo (file_exists($log_path))?"yes\n":"no\n";
} else {
echo "file unwritable\n";
}
This code works fine for me (yes, it's also messy ;) ).
file_exists caches the result of the operation, you should call clearstatcache() before the second call
for me it was promises issue solve it with
chown -R www-data:www-data /var/www/
chmod -R g+rwx /var/www/
chmod -R 0755 /var/www/
make sure that php run under user www-datain www.conf e.g I'm using PHP 7.2
nano /etc/php/7.2/fpm/pool.d/www.conf
Change these values :-
listen.owner = www-data
listen.group = www-data
unlink function in my case just returned false everytime. first, thanks to Viktor for this:
Also, add next line to begin of your script to show all errors and warnings: ini_set( 'error_reporting', E_ALL );
It helped me to see warning:
unlink(): http does not allow unlinking in PHP.
And i finally found the solution, described here https://a1websitepro.com/warning-unlink-http-not-allow-unlinking-php/.
The case is that i user http path to the file, but unlink function requires the absolute path to the file from your server.

PHP move_uploaded_file() error?

I using following code and it is successfully uploading files on my local machine. It is showing "Successfully uploaded" on my local machine.
// Upload file
$moved = move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . "myFile.txt" );
if( $moved ) {
echo "Successfully uploaded";
} else {
echo "Not uploaded";
}
But when I used this code on my online server then it is not uploading file and just showing message "Not uploaded".
How can I know that what is the problem and how can I get the actual problem to display to the user ?
Edit the code to be as follows:
// Upload file
$moved = move_uploaded_file($_FILES["file"]["tmp_name"], "images/" . "myFile.txt" );
if( $moved ) {
echo "Successfully uploaded";
} else {
echo "Not uploaded because of error #".$_FILES["file"]["error"];
}
It will give you one of the following error code values 1 to 8:
UPLOAD_ERR_INI_SIZE =
Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
UPLOAD_ERR_FORM_SIZE =
Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
UPLOAD_ERR_PARTIAL =
Value: 3; The uploaded file was only partially uploaded.
UPLOAD_ERR_NO_FILE =
Value: 4; No file was uploaded.
UPLOAD_ERR_NO_TMP_DIR =
Value: 6; Missing a temporary folder. Introduced in PHP 5.0.3.
UPLOAD_ERR_CANT_WRITE =
Value: 7; Failed to write file to disk. Introduced in PHP 5.1.0.
UPLOAD_ERR_EXTENSION =
Value: 8; A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop; examining the list of loaded extensions with phpinfo() may help.
Try this:
$upload_dir = $_SERVER['DOCUMENT_ROOT'] . '/images/';
if (is_dir($upload_dir) && is_writable($upload_dir)) {
// do upload logic here
} else {
echo 'Upload directory is not writable, or does not exist.';
}
This will instantly flag any file permission errors.
Check that the web server has permissions to write to the "images/" directory
How can I know that what is the problem
Easy. Refer to the error log of the webserver.
how can I get the actual problem to display to the user ?
NEVER do it.
An average user will unerstand nothing of this error.
A malicious user should get no feedback, especially in a form of very informative error message.
Just show a page with excuses.
If you don't have access to the server's error log, your task become more complicated.
There are several ways to get in touch with error messages.
To display error messages on screen you can add these lines to the code
ini_set('display_errors',1);
error_reporting(E_ALL);
or to make custom error logfile
ini_set('log_errors',1);
ini_set('error_log','/absolute/path/tp/log_file');
and there are some other ways.
but you must understand that without actual error message you can't move. It's hard to be blind in the dark
move_uploaded_file() will return:
FALSE if file name is invalid
FALSE and issue a warning in the error log if the apache process does not have read/write permissions to source or destination directories
PHP Error Log
My php error log was at: /var/log/httpd/error_log and had these errors:
Warning: move_uploaded_file(images/robot.jpg): failed to open stream: Permission denied in /var/www/html/mysite/mohealth.php on line 78
Warning: move_uploaded_file(): Unable to move '/tmp/phpsKD2Qm' to 'images/robot.jpg' in /var/www/html/mysite/mohealth.php on line 78
move_uploaded_file() tries to move files from a temporary directory to a destination directory. When apache process tried to move files, it could not read the temporary or write to the destination dir.
Find which user is running Apache (Web Server)
Check which user is running the apache service by this command: ps aux | grep httpd. The first column is the user name.
Check Read Permission at Temporary Dir: Your can find the path to your temp dir by calling echo sys_get_tmp_dir(); in a php page. Then on the command line, issue ls -ld /tmp/temporary-dir to see if the apache user has access to read here
Check Write Permission at Destination Dir: issue ls -ld /var/www/html/destination-directory to see if the apache user has access to write here
Add permissions as necessary using chown or chgrp
Restart Apache using sudo service httpd restart
Do you checks that file is uploaded ok ? Maybe you exceeded max_post_size, or max_upload_filesize. When login using FileZilla you are copying files as you, when uploading by PHP wiritng this file is from user that runs apache (for exaplme www-data), try to put chmod 755 for images.
or run suexec and never have to change permissions again.
In php.ini search for upload_max_filesize and post_max_size. I had the same problem and the solution was to change these values to a value greater than the file size.
Please check that your form tag have this attribute:
enctype="multipart/form-data"
$uploadfile = $_SERVER['DOCUMENT_ROOT'].'/Thesis/images/';
$profic = uniqid(rand()).$_FILES["pic"]["name"];
if(is_uploaded_file($_FILES["pic"]["tmp_name"]))
{
$moved = move_uploaded_file($_FILES["pic"]["tmp_name"], $uploadfile.$profic);
if($moved)
{
echo "sucess";
}
else
{
echo 'failed';
}
}
On virtual hosting check your disk quota.
if quota exceed, move_uploaded_file return error.
PS : I've been looking for this for a long time :)
Please check permission "images/" directory
I ran into a very obscure and annoying cause of error 6.
After goofing around with some NFS mounted volumes, uploads started failing.
Problem resolved by restarting services
systemctl restart php-fpm.service
systemctl restart httpd.service

Categories