Some servers want permissions at 777, some block any files at more than 755, some block the chmod function you want to use to change it anyway, etc etc. I want to use file_get_contents to write simple files to servers, but in scripts that are going to be distributed and used on many different servers that are quite varied. Assuming at least PHP5, what is the most "cross-server" and "cross-host" way to write/overwrite a simple text file? I was previously using something like this:
@chmod($filePath, 0755);
$result = file_put_contents($filePath, $fileData);
assuming it would work on as many servers as possible: set the permissions right if you can, but without errors if you can't (cuz some servers the file_put_contents works fine but it throws an error at the chmod that wasn't actually needed, but other servers need the chmod). But there has to be a solution that works on dang near every server imaginable (assuming PHP5+). Does anyone here have more experience with a better way?
CLARIFICATIONS:
I'm not expecting anyone to save the world, maybe it can't work for EVERY server, but we can still make it work on as many as possible, and that's what I'm hoping to accomplish. Lets at least exhaust all ways of solving as many problems as we can, and attempting to write it in as many ways as we can.
For example:
file_put_contents($filePath, $fileData);
Writes files. Yay! But on some servers or in some situations it may fail because of file permissions. Dang. So lets make it a bit better.
chmod($filePath, 0777);
file_put_contents($filePath, $fileData);
Now it changes the permission first! Cool, works on a few more people's servers! But wait, some servers reject 0777, so maybe 0755 is going to work for a few more servers than 0777 would.
chmod($filePath, 0755);
file_put_contents($filePath, $fileData);
Sweet, now it works for more people's servers. But wait: some servers block the chmod function. But that doesn't mean that the file isn't writable already, that was just a backup just in case it wasn't writable, so still at least try to write it, but make it not throw errors on the servers where chmod doesn't work, since it may very well work anyway (and we can always test whether it did afterwards so it doesn't fail silently).
@chmod($filePath, 0755);
file_put_contents($filePath, $fileData);
etc etc etc. See how I'm adding functionality to try more ways of making it work while making sure I don't break places where it already would have worked? I'm not asking anyone to "make chmod work no matter what". I'm asking if anyone has experience continuing down this path of thought, has found more places where file writing fails that can be avoided and accounted for them in a snippet of theirs until it is the best file writing snippet that it can be, working in as many places as it can. Maybe not everywhere, but in more places that the above snippet does. I know there's gotta be someone with experience on more varied server environments than me and can do it (or already has done it) better than I can, so I'm asking!
ADDITION BASED ON FEEDBACK:
1) One feedback is that permissions don't work different on different servers. Technically, yes. But in certain ways it's not that simple.
Some servers are set up to...rebel is as good a word as any...if you set your file permissions more loose than 755, such as 777, and not let the file be read/written/executed at all, just return a 500 error. On other servers, your php code seems to not be the "owner" of the file according to the server, and in that case I'm assuming group needs to be 7 as wall, or the file ownership would need to change (which brings up a whole other group of "cross-server" intricacies). I admit I could be understanding the root of what's going on incorrectly (and that's yet another thing I'm hoping to clear up if that's the case, someone having a deeper understanding of the problem and presenting a more elegant solution because of it!), but I can very much tell you that simply trying to set the permissions to 755 and then use file_put_contents very much does not work on every server as it should in theory (in fact I'd say it only works on about 90%-ish of the servers my clients have installed this type of code snippet on). So I'm asking if anyone has dealt with many servers in this way, and has a more bullet-proof method: one that can make it's way around the various differences between how random hosts set up their servers. I'd assume it would have multiple steps of first ensuring that the file is writable and then multiple attempts at various ways of writing the file itself.
2) and yes, the file needs to persist, that is the whole point :) Such as editing an XML file or creating a new html page within a CMS. And to nip this in the bud: don't give me "you should be using databases for info, not writing files". That has it's place too, I'm asking a different question though, about writing files, because sometimes you need to do that too :P
3) I get that there are situations where you simply won't be able to write the file. But what I'm asking is if anyone has experience with minimizing that so that it works in as many situations as possible. I know what I have above isn't the most universal snippet humanly possible, so I'm asking what might be :)
/tmp
is world writeable and available to every server. Do you need the files to persist - Mike Purcell 2012-04-04 23:58
I'm not an expert on the differences between servers, so that's why I was hoping to get an answer from someone who was, but apparently creativity of coding isn't a forte of the PHP community :) So I wrote one myself, and while infinitely better than just calling chmod then file_put_contents, I'm not a server expert and I assume it can be better...but it's better than nothing. (script works on over 99% of servers I've tested on, as opposed to the 85%-90% that just calling chmod then file_put_contents was working on).
function makeFileWritable($filename, $perm = 0755)
{
if (!file_exists($filename))
{
$folderpath = dirname($filename);
if(is_writable($folderpath)) return true;
@chmod($folderpath, $perm);
if(is_writable($folderpath)) return true;
if ($perm == 0755) return makeFileWritable($filename, 0775);
return false;
}
else
{
$folderpath = dirname($filename);
if(is_writable($folderpath) && is_writable($filename)) return true;
if (!is_writable($folderpath)) @chmod($folderpath, $perm);
if (!is_writable($filename)) @chmod($filename, $perm);
if (is_writable($folderpath) && is_writable($filename)) return true;
if ($perm == 0755) return makeFileWritable($filename, 0775);
return false;
}
}
@makeFileWritable($filePath);
$result = file_put_contents($filePath, $writeData);
Basically you call @makeFileWritable on the intended file path. If the file exists it tries to set the file permissions and the permissions of the folder containing it to 0755, and if the file doesn't exist yet it just tries to change its containing folder's permissions to 0755. Once that is done it tries to ascertain whether or not the file is now writable. If it is, then it is finished. If not then it calls itself again (in a sort of recursive manner) but this time trying to do the same thing with 0775 in case the server needs it to be group writable to work. But no matter what, it returns no errors and still tries to write the file, in case the file was writable all along but our tests to ascertain whether it was writable weren't accurate (and it's ok that the first part fails silently if it fails, because the actual file write won't be silent, and it's the part we really need to know if it worked or not).
So there you go, that script made it so that my 1 or 2 out of 10 servers that weren't writing files turned into basically 0 servers that weren't writing files...and an AS3/JS programmer wrote it after a bunch of PHP programmers told him the problem didn't exist or was unsolvable. I think some more creativity needs to be injected into the PHP community, and I hope they get a bit of a creative streak going and suggest some improvements, cuz I doubt as a non-php expert I have this as good as it can be :(
chmod
the file, it doesn't have access tochmod
the file - rdlowrey 2012-04-04 23:58