Since the title of this post is pretty much self-explanatory, I'll just jump to the code :
echo sprintf('%o', fileperms('test.txt'))."<br/>";
fopen("test.txt", "w");
And with this I get :
100777
fopen(test.txt): failed to open stream: Permission denied
Any ideas ?
Edit : Problem solved : there were access control lists on the server that were not configured correctly.
Thanks !
I think its possible that you have write/read permissions on the file but not on the folder. Try this in the public root of your website and see if you can read or write the file.
For safe mode (http://php.net/manual/en/function.fopen.php), php doc's say the following:
Note: When safe mode is enabled, PHP checks whether the directory in
which the script is operating has the same UID (owner) as the script
that is being executed.
Last you also need to be sure that php has access to the folder you are trying to write to.
I had same issue: folder was 777, but fopen does not worked. fopen said permission deny. Make sure your script have a 'good' permissions. maybe it will help you:
echo $dst, file_exists($dst) ? ' exists' : ' does not exist', "\n";
echo $dst, is_readable($dst) ? ' is readable' : ' is NOT readable', "\n";
echo $dst, is_writable($dst) ? ' is writable' : ' is NOT writable', "\n";
$fh = fopen($dst, 'w');
if ( !$fh ) {
echo ' last error: ';
var_dump(error_get_last());
}
I think the problem you are having is file ownership issue ... you can use this to find out the problem
error_reporting(E_ALL);
ini_set('display_errors','On');
$file = "a.jpg";
echo sprintf ( '%o', fileperms ( $file ) ), PHP_EOL;
echo posix_getpwuid ( fileowner ( $file ) ), PHP_EOL; // Get Owner
echo posix_getpwuid ( posix_getuid () ), PHP_EOL; // Get User
if (is_file ( $file )) {
echo "is_file", PHP_EOL;
;
}
if (is_readable ( $file )) {
echo "is_readable", PHP_EOL;
;
}
if (is_writable ( $file )) {
echo "is_readable", PHP_EOL;
}
fopen ( $file, "w" );
I just ran into this issue, and unfortunately the error message provided no clue to the actual reason. I had to give 777 to the file of the class included in the file that gave the error message. The error message only said the php file that calls that class, which already had 777.
So, check the file that is mentioned in the error message (let's say index.php), and then check which classes are instantiated within that file (class-file.php, class-writer.php, etc). Then check the permissions of those files (class-file.php, class-writer.php).
Once I gave permissions for the class file, it worked normally. Perhaps the webhost changed something in their config, since everything worked until a few days ago.
Related
What I'm trying to do:
Use PHP ftp_nlist to retrieve the contents of a directory on the FTP server
The problem:
For directories that contain a lot of files (the one I encountered the problem on has nearly 40 thousand files, and no subfolders), the ftp_nlist function is returning false. For directories that are not as large, the ftp_nlist function returns an array of filenames as expected.
What I've tried:
Enabling passive mode (it already was enabled, but I see it as a common suggestion)
Adding ftp_set_option($conn_id, FTP_USEPASVADDRESS, false); after my ftp_login
using ftp_chdir, although my folder names never have spaces anyways
echoing error_get_last() after ftp_nlist returns false. The error show seems unrelated, but is shown below.
My code:
In case it is useful, here is the function I have created. What it is supposed to do is...
take in $fm (filemaker, unrelated to this problem)
take in $FTPConnectionID (the ftp connection I established in the prior to the function call)
take in $FolderPath (the path of the folder on the FTP server for which I want to list files/subfolders recursively - ex: "SomeFolder/Testing")
take in $TextFile (I am writing the paths of every file found on the FTP server to a text file, which was created prior to calling the function)
function createAuditFile($fm, $FTPConnectionID, $FolderPath, $TextFile) {
echo "createAuditFile called for " . $FolderPath . "\n";
//Get the contents of the given path. Will include files and folders.
$FolderContents = ftp_nlist($FTPConnectionID, $FolderPath);
if($FolderContents == false) {
echo "Couldn't get " . $FolderPath . "\n";
echo "ERROR: " . print_r(error_get_last()) . "\n";
} else {
print_r($FolderContents);
}
//Loop through the array, call this function recursively if a folder is found.
if(is_array($FolderContents)) {
foreach($FolderContents as $Content) {
//Create a varaible for the folder path
$ContentPath = $FolderPath . "/" . $Content;
//Call the function recursively if a folder is found
if(pathinfo($Content, PATHINFO_EXTENSION) == "") {
createAuditFile($fm, $FTPConnectionID, $ContentPath, $TextFile);
echo "Recursive call for " . $ContentPath . "\n";
//If a file is found, add the file ftp path to our array
} else {
echo "Writing to file: " . $ContentPath . "\n";
fwrite($TextFile, $ContentPath . "\n");
}
}
}
}
I can provide other code if needed, but I think my question is less of a coding issue, and more of an understanding ftp_nlist issue. I've been stuck on this for hours, so any help is appreciated. And like I said, this function works just fine for most folder paths passed to it, the problem is when there are tens of thousands of files within the folder. Thank you!
Here is my simple code
$dst = "otps/hello.txt";
echo $dst, file_exists($dst) ? ' exists' : ' does not exist', "\n";
echo $dst, is_readable($dst) ? ' is readable' : ' is NOT readable', "\n";
echo $dst, is_writable($dst) ? ' is writable' : ' is NOT writable', "\n";
$fh = fopen($dst, 'w');
if ( !$fh ) {
echo ' last error: ';
echo '<pre>';print_r(error_get_last());echo'</pre>';
}
My current directory is set to 0777 but still the error, I created file manually and set permission to 0777 and still the same error.
here is output
Please note, I have setup my VPS server myself on digital ocean. I tried changing chown of the whole directories and files to apache, root, nobody but nothing is working.
running command
setenforce 0
works for me, not sure why :)
What I am trying to do
Connect to FTP server
Create new directories
Upload file into one of those new directories
What's going wrong?
Ok, so there is nothing wrong with the ftp connection, I am logging in with the credentials, switching to the relevant starting directory, which in this case is a directory on the server called "test".
At the start, this "test" directory is empty, as I just created it.
What I am then doing is taking a file from my local machine and attempting to upload that the remote path test/Folder1/Sub1/Sub2/Myfile.txt on the server.
To do this, I first split the path by "/" and check to see if I can switch to each of those directories, and if I can't, then I create them:
(You'll have to excuse the debugging dumps in the code)
// Split the path by directories and try and create all of them if they don't exist
$workingDir = $this->dir;
$newPath = str_replace($this->dir, "", $path);
$split = array_filter( explode("/", $newPath) );
if ($split)
{
foreach($split as $dir)
{
// Can we change to it?
if (!#ftp_chdir($this->conn, $workingDir . '/' . $dir)){
// Try and make the directory
if (!#ftp_mkdir($this->conn, $workingDir . '/' . $dir)){
var_dump("failed to make: " .$workingDir . '/' . $dir );
return false;
}
// Set the permissions to the default
$this->chmod = 0777;
ftp_chmod($this->conn, $this->chmod, $workingDir . '/' . $dir);
var_dump("Successfully made directory: " . $workingDir . '/' . $dir . " with permissions: " . $this->chmod);
}
$workingDir .= '/' . $dir;
}
}
This works fine, and I get the output of:
'Successfully made directory: /home/conn/test/Folder1 with permissions: 511' (length=74)
'Successfully made directory: /home/conn/test/Folder1/Sub1 with permissions: 511' (length=79)
'Successfully made directory: /home/conn/test/Folder1/Sub1/Sub2 with permissions: 511' (length=84)
If i exit at this point I can confirm the directories now exist on the remote server, with permissions of 0777
Next bit is to do the file upload into the new directory:
var_dump("Use this new name: {$newName}");
$filename = (($newName) ? $newName : $file->getFileName());
var_dump("working in remote directory: {$this->dir}");
var_dump("upload to remote: {$filename}, from: {$file->getFullPath()}");
// Change to that directory?
$split = explode("/", $filename);
$realFileName = array_pop($split);
$filedir = implode("/", $split);
var_dump("calling ftp_chdir() to : {$filedir}");
if (!#ftp_chdir($this->conn, $filedir)){
var_dump("couldn't change to {$filedir}");
return false;
};
var_dump( ftp_pwd($this->conn) );
var_dump("actual file name: " . $realFileName);
return ftp_put($this->conn, $realFileName, $file->getFullPath(), FTP_BINARY);
And again, this works fine. I get all the expected dumps:
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:121:string 'Use this new name: Folder1/Sub1/Sub2/Myfile.txt' (length=47)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:124:string 'working in remote directory: /home/conn/test' (length=44)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:125:string 'upload to remote: Folder1/Sub1/Sub2/Myfile.txt, from: C:\Ampps\www\duckfusioncore\app\lotto\tmp\tmp-nsEMH1RsDX' (length=110)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:131:string 'calling ftp_chdir() to : Folder1/Sub1/Sub2' (length=42)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:139:string '/home/conn/test/Folder1/Sub1/Sub2' (length=33)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:140:string 'actual file name: Myfile.txt' (length=28)
C:\Ampps\www\duckfusioncore\app\lotto\controllers\IndexController.php:28:boolean true
All the directories exist. The file is uploaded. All is well.
Except, if I now change the path I want to upload to and change toa new sub directory, which doesn't yet exist, e.g: Folder1/Sub1/NewSub/Myfile.txt
This is where it all goes wrong.
So the script runs through the create directory part again, and it successfully creates the new directory "NewSub", with the exact same permissions as before, and I can confirm that the directory exists on the remote server.
Except now when we get to the upload part, even though the directory exists, and this worked previously as we saw, it is unable to change to that new directory:
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:121:string 'Use this new name: Folder1/Sub1/NewSub/Myfile.txt' (length=49)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:124:string 'working in remote directory: /home/conn/test' (length=44)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:125:string 'upload to remote: Folder1/Sub1/NewSub/Myfile.txt, from: C:\Ampps\www\duckfusioncore\app\lotto\tmp\tmp-XJYdx8eduL' (length=112)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:131:string 'calling ftp_chdir() to : Folder1/Sub1/NewSub' (length=44)
C:\Ampps\www\duckfusioncore\sys\lib\helpers\datastore\stores\FTPStore.php:135:string 'couldn't change to Folder1/Sub1/NewSub' (length=38)
C:\Ampps\www\duckfusioncore\app\lotto\controllers\IndexController.php:28:boolean false
The directory 100% exists. And it has the same 0777 permissions as the other ones.
I'm just very confused as to why it is unable to switch to the directory, when it defintely exists and it has the same permissions as the other directories, which it had no problem switching to before...
Has anyone got any clue what might be the problem? Is there any extra debugging I can do on the ftp_chdir() function call to see if it gives me a reason?
Thanks.
ANSWER I WENT WITH BELOW!
So I have a PHP script that works prefect via the web. I would like to set it up on a scheduled task on the server that is running the web hosting. It is a windows 2008 R2 server. I seems to run fine minus the fact it won't make the output files. Do I need to have the full path name? Ex C:\logs.... or will below work? I would like to keep the script working both in web and command line.
$File3 = "" . $log_dir . "/" . date('m-d-Y') . ".txt";
$Handle3 = fopen($File3, 'a+');
$Data3 = "blah";
fwrite($Handle3, $Data3);
more info:
here are the errors from the log file:
fwrite() expects parameter 1 to be resource, boolean given in C:\Websites\wordpress\win\import.php on line 686
PHP Warning: file_get_contents(bins/bins-10-09-2013.txt): failed to open stream: No such file or directory in C:\Websites\wordpress\win\import.php on line 692
PHP Warning: fwrite() expects parameter 1 to be resource, boolean given in C:\Websites\wordpress\win\import.php on line 699
PHP Warning: fclose() expects parameter 1 to be resource, boolean given in C:\Websites\wordpress\win\import.php on line 709
WORKING!! Well, this is what I went with and it seems to work prefect.
$File = "" . $uploads_dir . "/import-" . date('m-d-Y-g-ia') . ".txt";
$Handle = fopen($file1, 'a+');
if ( $Handle === false ) {
$File = "C:\Websites\wordpress\win\\".$uploads_dir."\import-" . date('m-d-Y-g-ia') . ".txt";
$Handle = fopen($File, 'a+');
}
This way I can Use the php script both via web and on a scheduled task via windows.
It seems fopen is failing to open the file . Make sure the file is successfully opened :
$Handle3 = fopen($File3, 'a+');
if( $Handle3 === false ) echo 'Unable to open file';
If it fails , check below items one at a time :
Check file / folder permissions .
Check with different slashes "/" , "\" in the path .
Check if it works with absolute path ( full path ) .
Check by changing directory before fopen : chdir('path\to\php\script')
etc .
If the issue is with the path , one way make it work both cases is :
// First try with the path that works from web
$File3 = "" . $log_dir . "/" . date('m-d-Y') . ".txt";
$Handle3 = fopen( $File3, 'a+' );
if( $Handle3 === false )
{
// It failed so may be scheduled task invoked the script
// So use the path that works in invoked by scheduled task
$File3 = "path\that\works\from\command\line";
$Handle3 = fopen( $File3 ,'a+' );
}
if( $Handle3 === false )
{
echo 'Failed to open file';
exit;
}
else
{
// What ever
}
I've never used the full url for an fopen or fwrite. These are the things I would look at first:
What is the output when you echo $log_dir?
Does the directory exist?
Are permissions set correctly?
If you create the file before running the script, does it then successfully write to the file?
What is the value of $Handle3 after the fopen?
What is the return value of the fwrite that you call on the last line?
Is error handling set to all? (it should be for debugging)
I have a simple script that all I need it to do is create a directory with the name of the GET variable. When I run this script, it doesn't seem to create the directory. I would like this directory to be in the same directory as the PHP file.
$dir = $_GET['dir'];
umask(000);
mkdir($_SERVER['DOCUMENT_ROOT']."/".$dir."/",0777);
Put some error handling in there. Most of the time the error is self evident. The following snippet, lifted from PHP manual, shows you how.
$rs = #mkdir( $dirPath, 0777 );
if( $rs )
{
// success
}else{
// print error information
echo 'an error occurred. Attempting create folder';
echo '<br>dirPath: ' . $dirPath;
echo '<br>php_errormsg: ' . $php_errormsg;
}