We recently upgraded our server to cPanel 78 and migrated from EA3 to EA4. Our server only has two sites on it, and prior to the upgrade we could use PHP scripts to copy files between the two sites using PHP's file_exists() and copy() functions.
We could use the file_exists() function to grab files from site1 and migrate them to site2 using code similar to this:
$current_path = '/home/site1/public_html/uploads';
$new_path = '/home/site2/public_html/uploads';
if(file_exists($current_path.'/v2n62l6v.jpg')) {
echo 'File exists: true' . "\n\n";
copy($current_path.'/v2n62l6v.jpg', $new_path.'/2020/03/30/v2n62l6v.jpg');
} else {
echo 'File exists: false' . "\n\n";
}
This code also creates new directories and sets the permissions to 0755.
After the upgrade, when we attempt to execute the script, we are greeted with this error:
File exists: true
Warning: copy(/home/site2/public_html/uploads/2020/03/30/v2n62l6v.jpg): failed to open stream: Permission denied in /home/site2/public_html/move.php on line 15
We are able to move the files if we set the permissions to the folders to 0777, but I would prefer to not have to change all of the folder permissions (there are 10s of thousands).
Any ideas on where to start or what settings may have changed during the upgrade to either EA or cPanel/WHM?
Site is using:
PHP 5.5 (ea-php55)
DSO PHP Handler
CENTOS 6.10
cPanel v78.0.47
I am happy to provide any other information to help trouble shoot this issue.
Thanks so much for any/all help.
As you said that it is CentOS so the following should work
<?php
$current_path = '/home/site1/public_html/uploads';
$new_path = '/home/site2/public_html/uploads';
//Below command will copy paste all folders recursively
shell_exec("cp -r $current_path $new_path");
echo "All Done";
?>
If the above one doesn't works for some reasons then try going to the SSH terminal directly and run that shell command with your paths.
As you mentioned in comments that you want to further process the files that could be done on site2 itself once all files are there you could scandir/is_dir to scan and process files. But that is different topic.
If you really need to do this you have to make sure php user owns both sites files - apparently this is not your case.
Alternatively you can use root user to copy files preserving ownership and permission or changing their owner and permission at the destination accordingly.
One other option is to umask user privileges before your operation; Is strongly recommended to revert umask value after operation is completed:
https://www.php.net/manual/en/function.umask.php
Ex:
$old = umask(0);
//your operation here
umask($old);
Related
I am using mkdir() to create new files in my code, but for some reason it is setting something called "daemon" as the admin. I cannot delete these files, edit, access, or even move these files. How can I change this from happening when creating files in my code?
<?php
$dir = 'myDir3';
// owner will be the user/group the PHP script is run under
if ( !file_exists($dir) ) {
mkdir ($dir, 0777);
}
file_put_contents ($dir.'/test.txt', 'Hello File');
$file = 'template.php';
if(file_exists($file)){
echo readfile($file);
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
ini_set("display_errors", 1);
copy($file, $dir.'/fake.php');
} else {
echo 'file does not exist';
}
?>
Eureka Edit(1):
Ok, thanks again #blueweimer , for clarifying that you are using XAMPP on MacOS (and not XAMPP-vm); because thanks to that clarification I was able to find the right answer to your question, which can be found here.
To elaborate on the answer found in the link:
By default, when creating any sort of folder or file in XAMPP in MacOS it uses the user and group found in the httpd.conf file (the d stands for "daemon", which is the name given to running processes in Unix systems (like Linux and Mac, Mac being a slant more differentiated from Unix but still carrying over some of the same terms)). So by changing the user and group found in this file you can change the user that keeps the server running. It's the user that Apache uses to access everything and anything inside XAMPP.
It's important to note that you are changing your access user when changing the file in httpd.conf; but that does not automagically change the owner of the files and folders that have already been created. According to the link above, these files are found in /Applications/XAMPP/xamppfiles/, you'd have to change the owner of the files and the folder itself to the new user you've changed it to in httpd.conf.
Do not change this user to your own, as any failure in security that can occur on XAMPP will allow anyone with access to your XAMPP server to access your user remotely.
Before Edit:
Firstly, if possible, please post a code snippet so that we may know how this is being accessed.
Secondly, I'd like to apologize for placing all of this in an answer(low reputation so I can't comment just yet), but judging by the mkdir manual page for php, it seems that it creates the directory with the user who's running it as the owner. Given that it's setting the owner to "daemon" and you are unable to access it, I believe it safe to assume that you are not establishing default permissions (0777) and are running the file as a daemon.
You could choose to change the permissions the folders are created with:
<?php
mkdir("/path/to/my/dir", 0777);
?>
Alternatively you could use the chown command to change the ownership from "daemon" to another user within the same php file you create the folders with:
<?php
mkdir("/path/to/my/dir", 0700);
chown("/path/to/my/dir", "username");
?>
This answer was given according to the information provided: you did not specify which webserver you're using (you've simply specified html), and you've not specified an OS, so my understanding ist that it is a Linux distribution (otherwise folder access would not be a problem with PHP but rather with the webserver's permissions).
I know this is a common issue but I haven't been able to single out the problem for my specific use case, so bear with me.
I have a simple PHP script send_id which simply sends an ID number and saves it to a TXT file on my RHEL server running Apache 2.4.6 with PHP 5.4.
The error message: Warning: file_put_contents(/var/www/html/id.txt): failed to open stream: Permission denied in /var/www/html/send_id.php on line 6
'1' written to server
The PHP script itself:
<?php
$id=$_GET['id'];
$stringData = "$id";
$file = file_put_contents('/var/www/html/id.txt', $stringData.PHP_EOL , FILE_APPEND |LOCK_EX);
echo "'$stringData' written to server";
?>
chmodding to 777 didn't do anything. Additionally, I checked to see ownership rights and noticed that the id.txt file is owned by the root user at both user/group level, and PHP is being run at root level.
Anyone have any suggestions? If its any help, this seems to have happened after a yum update
I resolved this issue by simply running chcon -Rt httpd_sys_content_rw_t on the directory where my troubled PHP script lived in.
The chcon command changes the SELinux context for files. However, changes made with the chcon command are not persistent across file-system relabels, or the execution of the restorecon command.
-Rt are to change the type of the directory and its contents, httpd_sys_content_rw_t is to give apache write access
source: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-working_with_selinux-selinux_contexts_labeling_files
Additional note
ls -alZ *
The -Z switch will work with most utilities to show SELinux security contexts
Try changing the owner of the folder and the file to (chown) to "www-data" or to "www-data:www-data" and see if it changes anything...
Use a relative file path from, Apache's "DOCUMENT ROOT" to reference files in PHP. It's Apache's permissions that matter, and for security reasons it is coded to inhibit access to files outside of DOCUMENT_ROOT.. (yes even though your path leads within it, Apache is blocked as soon as it sees the path starts with "/VAR" ..
Assuming this PHP script is in the same directory as id.txt file , just use
$file = file_put_contents('./id.txt', $str...
Or if the txt file was in a sub-directory
file_put_contents('./sub-dir/id.txt', $str...
Not only is it secure, it's a lot shorter to type too.
I created an application which has an caching script on an Windows/Wamp environment. This script's caching function is only allowed to run once at the same time.
To achieve this I used a 'locking file' with check to see if it exists.
On windows this script continues to work fine. But now it is moved to an Ubuntu environment is doesn't work.
<?php
date_default_timezone_set('Europe/Amsterdam');
ini_set('max_execution_time', 300);
ignore_user_abort(true);
$path = 'locked.txt';
if ($lock = fopen($path,'x+')) {
fwrite($lock,time());
fclose($lock);
sleep(10);
unlink($path);
}
?>
Error: fopen(locked.txt): failed to open stream: Permission denied
From the PHP documentation (paraphrased a bit):
x+ Create and open for reading and writing; place the file pointer at the beginning of the file. If the file already exists, the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file does not exist, attempt to create it. This is equivalent to specifying O_EXCL|O_CREAT flags for the underlying open(2) system call.
From your description you are attempting to use a file as a lock file using the "x+" flag to ensure you're not locking a file already locked.
The problem is that migrating from windows to *NIX systems (like Ubuntu) you will need to familiarise yourself with the difference in the permissions system.
The short story is:
Each file and folder "belongs" to a user.
The user who wants to create a file in a directory needs at least an execute and write permission on that directory.
Having this in mind you need to ensure that the current user has write and execute permissions on the directory with the script and to actually execute the script they will also need read permissions on the directory (in addition to read permissions on the script). Ensure that the directory has read-write-execute permissions (flag no. 7) for the user running the script.
If you're running the script via a web interface this user will be www-data .
In general chmod 777 /directory/with/script should work and grant read-write-execute permissions on the directory for all users.
EDIT 1
This question involves the user of the MANGOPAY API. My problem is that I cannot get the API to write to the tmp folder.
I have succeeded in getting the API to write to http://fakedomain.com/apifolder/blank.txt and getting the appropriate output.
I then ran the script http://fake.com/apifolder/demos/iswrite.php on http://fakedomain.com/apifolder/blank.txt to have minimal working code I could test on the tmp folder. Here is the code in the script:
<?php
$filename = 'blank.txt';
echo "<br>";
file_exists($filename);
echo "<br>";
if (file_exists($filename)) {
echo "The file $filename exists";
} else {
echo "The file $filename does not exist";
}
echo "<br>";
if (is_writable($filename)) {
echo 'The file is writable';
} else {
echo 'The file is not writable';
}
?>
It gives me the output
The file blank.txt exists
The file is writable
so all good there. I created the following file with the following permissions using Filezilla:
In the script http://fake.com/apifolder/demos/iswrite.php I have changed the filename variable to $filename = 'http://fake.com/tmp/creative/blank.txt';. It gives me the following output:
The file http://fake.com/tmp/creative/blank.txt does not exist
The file is not writable
Also, allow_url_fopen is on.
I don't fully understand URL structures, so maybe the problem lies there? The tmp folder I am trying to access is on the same level as my public_html folder. Maybe I am writing my URLs wrong?
Put in another way, does the tmp folder have to be outside the public_html folder? Would there be any purpose to this? Or can I have create my own tmp folder within public_html where it is already working?
ORIGINAL QUESTION
The original question was poorly written. Please see EDIT 1
I am playing with the sandbox of an API (MangoPay). I have included my ClientId and ClientPassword which seems to work.
The API also says...
You also need to set a folder path in $api->Config->TemporaryFolder
that SDK needs to store temporary files. This path should be outside
your www folder. It could be /tmp/ or /var/tmp/ or any other location
that PHP can write to.
I have created one at:
ftp://fakedomain#fakedomain/tmp/fakefoldername
I am running the php script from my desktop using Terminal. The output it is giving me is
Cannot create or write to file
ftp://fakedomain#fakedomain/tmp/fakefoldername
even though I have set permissions to 777.
Any idea of why I am getting this error?
I am guessing the library in question is this one, and the error you are getting is this exception:
if (!is_writable($this->GetPathToTemporaryFolder()))
throw new \MangoPay\Libraries\Exception('Cannot create or write to file ' . $this->GetPathToTemporaryFolder());
So basically we seem to be debugging a call to is_writable().
make sure allow_url_fopen is on
if applicable, make sure the URL includes the FTP password
make sure the folder exists and the FTP account has write permissions (777 should suffice...)
Generally speaking a temp dir is supposed to be located on the same machine as your code. Using FTP is less than ideal. Are you not able to use a local directory?
You'll notice in the MangoPay documentation it shows a local dir:
https://github.com/Mangopay/mangopay2-php-sdk
$api->Config->TemporaryFolder = '/some/path/';
You should probably stick to that, instead of using a remote server via FTP.
An out-of-the-box Linux machine running Ubuntu 14.04 has the following user and permission settings
drwxrwxrwt 13 root root 4096 nov 9 00:56 tmp//
And the dummy directory
drwxrwxr-x 2 eric eric 4,0K nov 9 00:49 fakefoldername/
In case of switching to 777 permission set (as you said, you have already done this), that would be
drwxrwxrwx 2 eric eric 4,0K nov 9 00:49 fakefoldername/
The point to notice here is that if you used chmod 777 fakefoldername it changes the permission set only to the directory without touching any of the files/directories in fakefoldername (use chmod -R 777 fakefoldername). Another point to remember is that directories leading to the fakefoldername also need to have sufficient perms. For this particular case, check if /tmp folder has them, fix if necessary
sudo chmod 1777 tmp/
Also, as stated above, I would try to make another directory in /var directory and see how things are going then (an nice answer why to or not to choose /var/tmp over /tmp here).
For others: the SDK that is used is probably https://github.com/Mangopay/mangopay2-php-sdk
There might be some hints in the somewhat similar answers below:
http://forum.odin.com/threads/error-message-cant-create-write-to-file-tmp-after-overflow-tmp.296376/
https://unix.stackexchange.com/questions/39466/vsftpd-553-could-not-create-file-permissions
Most likely, your apache dont have permissions to write that folder, you have to be sure that you are creating that directory with same user (in your case, apache) and also chmod.
Im trying to unlink a folder on the local version of my site.
I get the error:
operation not permitted
Any ideas how I can get unlink to work on my local machine? Im using MAMP.
See the documentation:
unlink — Deletes a file
and
See Also: rmdir() - Removes directory
You have a directory. You need to use rmdir, not unlink.
It means the script is not allowed to delete the folder. This can have various reasons - the most likely one is that you are trying to unlink() a folder instead of using rmdir() to delete it.
Here are the possible reasons for "operation not permitted" (EPERM) from the unlink(2) man page:
EPERM The system does not allow unlinking of directories, or unlinking of directories requires privileges that the calling process
doesn't have. (This is the POSIX prescribed error return; as noted
above, Linux returns EISDIR for this case.)
EPERM (Linux only)
The file system does not allow unlinking of files.
EPERM or EACCES
The directory containing pathname has the sticky bit (S_ISVTX) set and the process's effective UID is neither the UID of
the file to be deleted nor that of the directory containing it,
and the process is not privileged (Linux: does not have the CAP_FOWNER capability).
This is a permissions problem.
Try giving the file you want unlink permissions like CHMOD 666.
You probably created the file yourself and want PHP (another user then yourself, probably Apache or www-data depending on how MAMP is installed) to delete the file for you - without the right permissions, this cannot be done.