Files cannot be uploaded


Symptoms

The FilesAction complains about not being able to sucesfully move_uploaded_file() after an upload, even though the upload directory has been created and has correct permissions:
Warning: move_uploaded_file() [function.move-uploaded-file]: SAFE MODE Restriction in effect. The script whose uid is 24822 is not allowed to access /uploads/SandBox owned by uid 99 in /actions/files.php on line 127
There was an error uploading your file.


Cause

PHP safe mode is activated, and the server and scripts run as different users.

Applies to


Version 1.1.6.0 (and very probably all earlier and future versions, since this is a "property" of the environment where the Wikka is run). This solution can only be applied when you have FTP acess to your website.

Solution


Instead of mkdir(), we have to create the directories using FTP. The following code was found in the comments to the mkdir() function on www.php.net.

Open the file actions/files.php and before the mkdir_r() function definition, add the following code:
// create directory through FTP connection
function FtpMkdir($path, $newDir) {
 
  $server='ftp.server.com';           // ftp server
  $connection = ftp_connect($server); // connection
 
 
  // login to ftp server
  $user = "me";
  $pass = "pass";
  $result = ftp_login($connection, $user, $pass);
 
  // check if connection was made
  if ((!$connection) || (!$result)) {
    return false;
    exit();
  } else {
      ftp_chdir($connection, $path);        // go to destination dir
      if(ftp_mkdir($connection, $newDir)) { // create directory
        ftp_site($connection, "CHMOD 775 $newDir") or die("FTP SITE CMD failed.");
        return $newDir;
      } else {
        return false;    
      }    
    ftp_close($connection); // close connection
  }  
}

Change the login information accordingly.

Now, find the following code (still in actions/files.php)
if (! function_exists('mkdir_r')) {
    function mkdir_r ($dir) {
        if (strlen($dir) == 0) return 0;
        if (is_dir($dir)) return 1;
        elseif (dirname($dir) == $dir) return 1;        
        return (mkdir_r(dirname($dir)) and mkdir($dir));
    }
}


and change it to
if (! function_exists('mkdir_r')) {
    function mkdir_r ($dir) {
        if (strlen($dir) == 0) return 0;
        if (is_dir($dir)) return 1;
        elseif (dirname($dir) == $dir) return 1;        
        return (mkdir_r(dirname($dir)) and FtpMkdir('/PathToWikkaDirOnFTP',$dir));
    }
}

(Note: Don't forget to change the '/PathToWikkaDirOnFTP' according to your set-up. I believe that a simple '/' will probably sufficient in the majority of cases)

Refinement

This could be refined so that a new FTP connection isn't created for every directory we're creating recursively. Also, the parameters could probably be placed in wikka.config.php but since this is a very specific fix for a very specific situation, I don't think it's worth the effort. And lastly, the FtpMkdir() function could be placed in a conditional block to prevent it from being redeclared (but how real that possibility is, I don't know).

CategoryWorkaround
Comments
Comment by DarTar
2005-11-29 10:45:52
Hi CyneBeald and welcome to Wikka. Thanks for contributing this workaround. You might want to create your userpage and tell us more about you and the way you use Wikka.
Comment by CyneBeald
2005-11-29 12:42:52
Hi, thanks. I hope I'll get to create my userpage sometimes soon. We're trying to use Wikka as a project and content management system, we're still getting the hang of it.
Comment by JoNol
2006-10-07 06:00:00
Hello!

I don't like to tell a script my master ftp password for my site.

In safe_mode you can't create new directories, so I propose the following solution, but I'm not an expert!

1. Create via ftp an upload directory uploads with full write access for all.

2. Replace in actions/files.php:

a) line 77 ff
$upload_path = $this->config['upload_path'].'/'.$this->GetPageTag();

if (! is_dir($upload_path)) mkdir_r($upload_path);

by: $upload_path = $this->config['upload_path'];

b) line 96

$destfile = $upload_path.'/'.$strippedname;

by: $destfile = $upload_path.'/'.$this_GetPageTag().'_'.$strippedname;

3. Replace in handlers/page/files.xml.php

$upload_path = $this->config['upload_path'].'/'.$this->GetPageTag();

if (! is_dir($upload_path)) mkdir_r($upload_path);

by: $upload_path = $this->config['upload_path'];

All uploaded files are now stored in one dir, but filename links to the page!

Maybe I told nonsense but in my environment it works!
Comment by QuEal
2008-03-10 17:22:40
JoNol's suggestion does work for me too, but you made a typing error in your code:
b) line 96

$destfile = $upload_path.'/'.$strippedname;

by: $destfile = $upload_path.'/'.$this_GetPageTag().'_'.$strippedname;

$this_GetPageTag() should be $this->GetPageTag()

This solution definitely solves the problem AND you don't need to tell your script your ftp password
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki