I'm trying to work with php system (exec) functions to run some commands on linux, but it just doesn't work!
I've logged into the system with root user. I created "/1.txt" file and then I ran this php script through apache server: system("sudo cp /1.txt /2.txt", $out); but it doesn't copy the file.
Can you explain why it doesn't work? (I'm new to linux os please explain)
Drop the sudo and give permissions to apache's user on /1.txt and /2.txt, it should work.
If /2.txt doesn't exist, create a directory, put 1.txt on that directory and give permissions to apache user both on the directory and on the file.
/1.txt and /2.txt are at the very top level of the filesystem - is that what you're aiming to do? Either way it's not a good idea.
I'd recommend having an area which your files are in, for example /var/webapp-files/ that way you can do something like:
define('WEBAPP_FILES_LOCATION', '/var/webapp-files');
system("cp ".WEBAPP_FILES_LOCATION."/1.txt ".WEBAPP_FILES_LOCATION."/2.txt", $out);
NOTE: I've defined a constant for the location because it'll be needed in a number of different places and you don't wanna start repeating yourself in case you want to change it any time.
What this'll do is run the system command:
cp /var/webapp-files/1.txt /var/webapp-files/2.txt
Which should succeed if your /var/webapp-files directory has write access for your apache user.
However... PHP does have a built-in function for copying which I'd recommend using instead of the more generic and dangerous system(). You can read about copy() at http://uk3.php.net/manual/en/function.copy.php This will need the full paths as cp does so you can refactor my previous example to:
define('WEBAPP_FILES_LOCATION', '/var/webapp-files');
$copySucceeded = copy(WEBAPP_FILES_LOCATION."/1.txt", WEBAPP_FILES_LOCATION."/2.txt");
echo "The copy attempt ". ($copySucceeded ? "succeeded" : "failed");
Hope that helps.
Related
I have this problem, I want to execute a cronjob but when I run the cron manually for testing I get permission issues.
I am using the Yii framework and I call the cronjob using Yiic. I want to create a directory structure where every directory contains an image. So we get like this:
/dir/id/
/dir/id/imgsize-1
/dir/id/imgsize-2
/dir/id/imgsize-3
It get's more complex because it could be that imgsize-3 exists while imgsize-1 doesn't. And it could be possible that /dir/id/ is not writeable (0755 perms) so I first need to check if the parent directory (/dir/id/) is writable. If so I should be able to use mkdir to create dir 'imgsize-1' or whatever is my thought so far.
But now the problem occurs that if I want to use chmod to make a the parentdirectory writable I get the error 'chmod: 'path/to/dir' operation not permitted' and after that ofcourse that mkdir results in 'Permission denied'.
How can I solve this. When I use ls -la on the specific directorie I want to make writable I get the following:
4 drwxr-xr-x 9 nobody nobody
Is there someone who can help me with this?
b.t.w. I execute the CLI-commands in PHP with shell_exec.
Kind regards,
Pim
in your command action you should have something like this:
$dir = '/your/path';
if (!is_dir($dir))
mkdir($dir, 0777, true);
Then, running the cron (what's the user you're running the command with?) with the command php yiic yourCommand, the directory should be created in /your/path
I am having problems with functions that create files in the tmp directory such as tmpfile() and tempnam(). They all seem to fail to write to tmp and return false. upload_tmp_dir is set in php ini and file uploads work fine.
When debugging this error I found that sys_get_temp_dir() gets the location of the tmp directory unfortunately it's not supported in my PHP version (5.1.6). I also saw that using the following method replaces the functionality of sys_get_temp_dir():
if ( !function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir() {
if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
$tempfile=tempnam(__FILE__,'');
if (file_exists($tempfile)) {
unlink($tempfile);
return realpath(dirname($tempfile));
}
return null;
}
}
But there is no reference to a tmp directory in the $_ENV array and tempnam() fails as I mentioned before.
Also open_basedir is not set which I've heard can cause similar problems
How can I find out where the tmp directory is or whether it is even set?
Is this a apache server configuration issue or a PHP one?
Thanks for your help
I am running Ubuntu 18.04 and I could create/modify files in the /tmp directory when I ran the PHP script from the CLI, but when I tried accessing the same script as a web page, I could never find the file that was being created. It turns out that Apache by default will create a private tmp directory. The following post provided some insight on the problem Odd Bits - Private /tmp directory. However, the /usr/lib/systemd directory mentioned in the post did not contain any services for http or apache2 on my machine. To help track down the problem I executed the following command:
sudo find / -mount -type f -exec grep -e "PrivateTmp" '{}' ';' -print
and found in /lib/systemd/system/apache2.service the PrivateTmp=true mentioned in the Odd Bits post. Copying the file from /lib/systemd/system to /etc/systemd/system/ and changing true to false and executing
systemctl daemon-restart
systemctl restart apache2
fixed the problem. A person wiser than me suggested copying the file to /etc instead of editing it in /lib was the correct course of action because /lib is 'owned' by the packages and local edits should be performed in /etc. systemd man page describes the systemd configuration processing in gory details.
you can set the upload temp dir in your php.ini -
something like that should work:
upload_tmp_dir=/your-www/tmp/
Also, in case you can't edit the php.ini or don't want to do it globally you can use this in the beginning of your script:
ini_set('upload_tmp_dir','/your-home-www/tmp/');
TMP, TEMP (and maybe TMPDIR) are valid on Windows only and usually pointing to C:\Windows\TEMP. On Linux default temp location is /tmp. To workaround this (works with tempnam() function) you can create a temp folder somewhere within your website space, specify appropriate access permissions and pass this as first parameter to the above function.
Not a great solution but better than nothing.
Probably not the cleanest but this works on my old 5.1.6 install:
function get_temp_path() {
static $path = null;
if ($path !== null) return $path;
$file = tmpfile();
$meta = stream_get_meta_data($file);
fclose($file);
$path = dirname($meta['uri']);
return $path;
}
I have the same problem and the solution is to change the apache configuration to expose the TEMP variable to PHP, see this post.
Tip for newbies like me: I THOUGHT that PHP couldn't move stuff from my temporary folder, but I was just confused because of the relative positions of folders. This may apply to someone else, so I'll explain, even though it's very tangentially related to this specific question (because this specific question is a likely search result for other people like me who are newbies).
My problem is that I was echoing an upload form FROM a functions.php file inside of /var/www/html/ TO a profile.php file in /var/www/html/user/ which CALLED an uploadphoto.php file in /var/www/html/. Uploaded files were ultimately intended to land in /var/www/html/uploads. This ultimately meant that most of my references to both uploadphoto.php AND uploads/ in functions.php were written "../uploadphoto.php" or "../uploads/[etc.jpg]", respectively, in order to step back into html/ from html/user/ (where the echoed code landed in html/user/profile.php). This led me to intuitively use the following command inside of uploadphoto.php without thinking it through:
move_uploaded_file($_FILES["file"]["tmp_name"][0], "../uploads/$filename")
See the problem? uploadphoto.php is in the same directory as uploads/, so I did not need the ../ here. For hours, I was sure I was messing up my folder permissions again, because I am new to image uploading. I had forgotten to check for more simple-minded errors. Hopefully this helps someone else.
As part of application logging, I'm attempting to open a local file, and if that file doesn't already exist, to create the new one. Here's what I have:
$path = '/home/www/phpapp/logs/myawesome_logfile.txt';
$f = (file_exists($path))? fopen($path, "a+") : fopen($path, "w+");
fwrite($f, $msg);
fclose($f);
chmod($path, 0777);
I've double-checked, and the /logs directory is chmod 0777, and I even went the extra step of chown'ing it to apache:apache for good measure. Still, when the script goes to open the file, it gives me the warning that the file doesn't exist and bombs out. No file is ever created.
Do I need to suppress the fopen() warning to get it to create the file?
When you're working with paths in PHP, the context can matter a great deal. If you're working with urls in a redirection context -- then the root directory ('/') refers to your domain's root. The same goes for paths for linking files or images and for include and require directives.
However, when you're dealing with file system commands such as fopen, the root directory ('/') is the system root. Not your domain root.
To fix this, try giving the full path to the log file you want to open from the system root. For example: /var/www/phpapplication/logs/myLogFile.txt
Or you could use $_SERVER['DOCUMENT_ROOT'] as suggested in other answers to access your server's stored value for the path to the document root. The /var/www part.
You can also use the __DIR__ magic constant in some cases. Note that __DIR__ will be the directory the current file is in, which is not necessarily the same as your application's root. So for example, if your application's root is /var/www/application and you're working in /var/www/application/src/controllers/my_controller.php, then __DIR__ will be /var/www/application/src/controllers. See here in the PHP documentation.
Have you tried this?
$msg = "I'm a line that is a message.\n";
$path = $_SERVER['DOCUMENT_ROOT'] . '/logs/myawesome_logfile.txt';
$f = fopen($path, "a+");
fwrite($f, $msg);
fclose($f);
chmod($path, 0777);
The server you're working on could have jailed you to only work in the phpapp's directory and its subdirectories.
One way I got around this problem in UBUNTU 14.04 was by right clicking on the directory where the file is located and changing the permissions of "others" to "create and delete files".
You can always open your file with just "a", it will create a new file as well.
No need to make a condition.
However, the main issue with your code is understanding the difference between physical filesystem and virtual web-server, which have been perfectly explained already.
Note that you should provide your question with exact copy of error message. It contains a ton of extremely useful information, it's not like an oath "I won't create your file, go away!" but it's through explanation of what and why is going wrong. If you don't care of such useful info yourself, you have to provide it to ones whom asking for help.
The path of the file must be with the server root. I could achieve this using the
phpinfo()
method inside the document I wanted to know. So when you use phpinfo() you will see a information document. If you find for
_SERVER["SCRIPT_FILENAME"] you will see the absolute path of your file.
I hope this help someone.
Don't forget to make sure that SELinux isn't blocking you.
[root#yourbox]# audit2allow < /var/log/audit/audit.log
#============= httpd_t ==============
#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:dir { write add_name };
#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:file { write create };
[root#yourbox]# audit2allow -a -M my_httpd
Note:
To make this policy package active, execute:
semodule -i my_httpd.pp
[root#yourbox]# semodule -i my_httpd.pp
[root#yourbox]# systemctl restart httpd
i was using this basic script:
$folderPath = "../path/to/$folder/";
mkdir("$folderPath");
i create this directory and then upload photos to it. I've been doing this for a good 4-5 months now and suddenly i start getting 'FORBIDDEN' errors when I attempt to view the contents of the folder via web browser
The directory is being created the same and the photos are still uploading without a problem, but I cannot access the photos
I tried rewriting the script and using chmod to change the permissions but I'm having no luck at all
All the older folders were being created with: -w- rwx r-x r-x
and I can't get this recreated
I've tried adding a chmod line into my script:
$folderPath = "../sales/inventory/$folder/";
mkdir("$folderPath");
chmod("$folderPath", 0755);
but I can't recreate the same permissions, I'm trying to understand how chmod works, but I can't figure out how to get this very basic function working properly again
Try looking out for a HTAccess file, where the "Options -Indexes" option will be mentioned, as this is mostly used for not showing the contents of a folder in a web browser. The file needs to be searched in the following manner:-
In the folder "root_folder/sales/inventory/$folder/", where "$folder" is as mentioned in your code.
If not found, try in the folder "root_folder/sales/inventory/".
If not found, try in the folder "root_folder/sales/".
If not found, try in the folder "root_folder/".
When you get the code of "Options -Indexes" written in the HTAccess file, you can remove / comment that line of code from there, or you can also write another HTAccess file in your required folder of "$folder", where the code will be "Options Indexes".
Also in the PHP page, the logic must be like this:-
<?php
$folderPath = "../sales/inventory/$folder/";
mkdir("$folderPath");
chmod("$folderPath", 0755);
// Use of "copy()" / "move_uploaded_file()" function here, using some "$targetFile" variable.
chmod($targetFile, 0755);
?>
This will help you when you will be unlinking / deleting the uploaded files from the "$folder" folder.
Hope it helps.
If your $folder variable includes some sub-directories your parent directories are maybe not being chmoded to the right permissions. This was the problem I was having on a hired OVH Gentoo server.
Imagine that $folder = '/store1/ally23/shelf42'; so your final directory structure is
../sales/inventory/store1/ally23/shelf42, and you want 0777 permisions.
You do:
mkdir($folderPath, 0777, true) || chmod($folderPath, 0777);
Only the final directory shelf42 is chmoded to 0777. The intermediary directories are created with default permissions (in my case 0744).
There is no recursive option in PHP's chmod command, so you have to loop over the intermediary directories and chmod them individually.
If you're in a shared environment, you may also want to chown after upload, to be on the safe side. Especially if you're running your web server under a user other than your virtual host has permission to access (EG: "nobody" vs "mysite".) This is common with cPanel servers, FWIW.
Simply umask means the default permissions for new files/directories:
<?php
umask(022);
?>
This sets the default permissions for user, groups, and others respectively:
0 - read, write and execute
1 - read and write
2 - read and execute
3 - read only
4 - write and execute
5 - write only
6 - execute only
7 - no permissions
I was wondering if there is some variable that will return what $_SERVER['DOCUMENT_ROOT'] returns when I call PHP like this: ./somescript
If not, how do people get around this case? I'm looking to be able to call the same script (a template compiler) in both the web browser and the terminal.
Thanks!
Matt Mueller
I don't recommend the getcwd() command for this because you cannot be sure of where cwd is pointing unless you've made a chdir before (which mean you already know which directory you're in). Working directory can be define in php config and vary between apache and CLI, and some php frameworks changes it on startup.
Use dirname(__FILE__) it always works wether you're in a apache or cli context (plus it works on windows and unix), and if you need to move inside your project files you can just use relative paths.
I think you should use getcwd function to obtain current directory (or just dirname(__FILE__) if your script is the top one). Then you only need to be sure to run the script from your DOCUMENT_ROOT. Something like this:
cd /var/www/
php ./scripts/top.php
hardcode document root in it.
hardcode is always a solution