I've installed drupal version 4.6.3 and almost everything is working except the image and upload modules.

When I try to create an image content I get the next error message: File copy failed: source file does not exist.

Background info:
I've drupal installed on at my hosting company which has PHP in safe mode. (4.3.11).
Drupal directory structure:
+---drupal
| +---database
| +---files (777)
| | +---images (777)
| | | +---temp (777)
| | | \---tmp (777)
| | \---pictures (777)
| +---includes
| +---misc
| +---modules
| | \---po
| +---scripts
| +---sites
| | \---default
| +---themes
| | +---bluemarine
| | +---chameleon
| | | \---marvin
| | +---engines
| | | +---phptemplate
| | | \---xtemplate
| | +---greenmarinee
| | \---pushbutton
| \---tmp

I'm able to upload files with the move_uploaded_file module with an phpupload.php script from my hosting party.
There are no errors in the settings of the image module of drupal. Default image path is "images".

What do I've to do to solve the image upload problem?

Regards,
Stefan

CommentFileSizeAuthor
#24 file-upload-safe.patch969 bytesanj
#10 file_0.inc17.48 KBsstrange
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Bèr Kessels’s picture

AFAIK tmp is relative to your OS root.
so /tmp is not files/tmp but the actual /tmp of your OS/server. So make sure you set the TMP relative to your files directory, or give an absolute path. Something like /var/ww/drupal/files/tmp

sstrange’s picture

I changed the Temporary directory settings from "tmp" to "/ext/s/st/stranger.nl/html/drupal/tmp" and saved the configuration. (no errors when saving settings)
But I still get the error File copy failed: source file does not exist.

Bèr Kessels’s picture

hmm; Sstrange.; (sorry could not resist ;) ) Can you see what permssions you have for the files _inside_ tmp? if tehre are any, that is. It could be that thefiles themselves have problems with permissions once put there
Other then that, I am afraid I cannot help you any further.

sstrange’s picture

I'm not sure what you mean with "files _inside_ tmp" but the permissions on html/drupal/tmp are 777. But there are no files within in tmp directory. But I can put files in that directory by ftp.

How do I know what the default tmp directory is from my hosting company?

Regards,
Stefan

Bèr Kessels’s picture

I meant files, that were stuck in that directory. Or might have been.
But the fact there are no files at all in that dir, should help a lot too.

Though I am lost at this moment.

walkah’s picture

Project: Image » Drupal core
Version: » 4.6.3
Component: image.module » file system

this seems to be a general file system issue - i'm suspicious of safe mode, but can't test further atm.

sstrange’s picture

Can anyone please tell me how the image module works? What are the actions when an image is uploaded? In which directories are the (temporary files) placed before they are placed in the right directory?

Regards,
Stefan

sstrange’s picture

According to the helpdesk of my hosting provider uses the file.inc (API for handling file uploads and server file management) the file_copy function which does not work with the safe mode restriction of my provider.

Is not it posible to use the move_uploaded_file function instead of the file_copy function?

If so who can help me?

Regards,
Stefan

cuebix’s picture

Category: support » bug

That is indeed the problem. I added a few lines of code inside of includes/file.inc to find out what was going on:

$source = realpath($source);
var_dump($source);
exit;
if (!file_exists($source)) {
drupal_set_message(t('File copy failed: source file does not exist.'), 'error');
return 0;
}

When uploading a file, this output:

string(14) "/tmp/phpz4d3CH"

The problem is, if you have safe_mode enabled, the conditional statement will fail. /tmp resides outside of the paths the script is allowed to work with, so even though the file exists, the function file_exists() plays dumb, as it should. The solution is, as suggested, to use move_uploaded_file instead.

I've created a workaround for it for Drupal 4.6.3

In includes/file.inc

in file_copy(...)
Line 231: if (!file_exists($source) && !is_uploaded_file($source)) {
drupal_set_message(t('File copy failed: source file does not exist.'), 'error');
return 0;
}

Line 272: if (is_uploaded_file($source)) {
if (!move_uploaded_file($source, $dest)) {
drupal_set_message(t('File copy failed.'), 'error');
return 0;
}
} else if (!@copy($source, $dest)) {
drupal_set_message(t('File copy failed.'), 'error');
return 0;
}

in file_move(...)
Line 314: if (is_uploaded_file($path_original)) {
$uploaded_file = true;
}
if (file_copy($source, $dest, $replace)) {
$path_current = is_object($source) ? $source->filepath : $source;
if ($uploaded_file || $path_original == $path_current || file_delete($path_original)) {
return 1;
}
drupal_set_message(t('Removing original file failed.'), 'error');
}

For some reason the regular upload module still won't work though.

sstrange’s picture

FileSize
17.48 KB

I changed the file.inc according to you advise but now I'm getting the next error message:
Parse error: parse error, unexpected $ in /mnt/storage2/s/st/stranger.nl/html/drupal/includes/file.inc on line 559

See attached file.inc

dmjossel’s picture

I have a similar experience with the same error message, although the ability to add new images and to upload files seems unaffected. Only the update-image.php script is affected.

Also, PHP is not running in safe mode:

http://drupal.org/node/31816

Given that new images can be added, and all the paths are correct and readable (as well as writeable in the case of the images and temp folders, and PHP safe mode is off, it seems that there may be another obscure issue.

The same server and web configuration works with Drupal 4.5's image module, as well.

walkah’s picture

Assigned: Unassigned » walkah

i'll look at a safe_mode work around

(/me waves to amsterdam)

ac’s picture

Just wondering if any solution was discovered for this. I moved a site to a server with safe_mode enabled and now i can't upload anything via the web interface.

teradome’s picture

Just agreeing with AC -- I am in the same predicament now, and I'm relying heavily on image.module.

teradome’s picture

cubix - i tried your code and also was not able to get it to function (got the white-screen-gone-to-server-log drupal error). please provide your working code as a patch file.

ac’s picture

cubix i also tried your code and it worked. but then it stopped working...then it started working.. now it has stopped working :( i cant understand how this could possibly happen but it has. this is a real pain

killes@www.drop.org’s picture

walkah, is this still a problem with our beta releases? If yes, please fix.

matt@antinomia’s picture

Title: File copy failed: source file does not exist. (image module) » Safe mode workaround?

I've been trying to fix this basted issue for a couple hours now. We just moved a 4.6.5 site onto its production server - which is running with safe mode enabled. All uploads are greeted by the error message: "File copy failed: source file does not exist." We've attempted cuebix's edits (although they are a little confusing) with no luck. Anybody else out there get this issue resolved using move_uploaded_file?

Thanks for the help!

sstrange’s picture

I've moved to a provider which doesn't have safe mode enabled ;-)

Regards,
Stefan

teradome’s picture

killes, i too am incredibly interested in whether or not the 4.7 work has fixed this problem.

forgette’s picture

I'm adding a me too to this item. Would very much like to have this fixed in next release. Thanks for your efforts!

bomarmonk’s picture

Any workaround? I am using Drupal 4.6.5 with and having the same problem with the paths-- all the permissions are correct and the modules like this. But when I upload a file I will get: "File copy failed: source file does not exist."

alexxed’s picture

I've changed a bit the function file_check_upload from /includes/file.inc and got the uploads working.

Before:

function file_check_upload($source) {
  if (is_object($source)) {
    if (is_file($source->filepath)) {
      return $source;
    }
  }
  elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
    $file = new StdClass();
    $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
    $file->filepath = $_FILES["edit"]["tmp_name"][$source];

After :

function file_check_upload($source) {
  if (is_object($source)) {
    if (is_file($source->filepath)) {
      return $source;
    }
  }
  elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
    move_uploaded_file($_FILES["edit"]["tmp_name"][$source],file_directory_temp()."/".$_FILES["edit"]["name"][$source]);
    
    $file = new StdClass();
    $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
    $file->filepath = file_directory_temp()."/".$_FILES["edit"]["name"][$source];
anj’s picture

Status: Active » Needs work
FileSize
969 bytes

Here's the same modification, as a patch against DRUPAL-4-7 in CVS.

teradome’s picture

This doesn't work for me. All I get is the white-screen-of-death (when choosing a file and previewing the node).

teradome’s picture

I've just checked the error log:

[Sun Jan 29 14:22:55 2006] [error] PHP Fatal error: Call to undefined function: file_directory_temp() in /home/www/vhosts/www.foo.net/htdocs/includes/file.inc on line 144
[Sun Jan 29 14:23:43 2006] [error] PHP Fatal error: Call to undefined function: file_directory_temp() in /home/www/vhosts/www.foo.net/htdocs/includes/file.inc on line 144

Your patch relies on a function not in 4.6.

alexxed’s picture

For 4.6.5, resolution would be :

Before:

function file_check_upload($source) {
  if (is_object($source)) {
    if (is_file($source->filepath)) {
      return $source;
    }
  }
  elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
    $file = new StdClass();
    $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
    $file->filepath = $_FILES["edit"]["tmp_name"][$source];

After:

function file_check_upload($source) {
  if (is_object($source)) {
    if (is_file($source->filepath)) {
      return $source;
    }
  }
  elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
    move_uploaded_file($_FILES["edit"]["tmp_name"][$source],FILE_DIRECTORY_TEMP."/".$_FILES["edit"]["name"][$source]);
    $file = new StdClass();
    $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
    $file->filepath = FILE_DIRECTORY_TEMP."/".$_FILES["edit"]["name"][$source];

@todo: gotta learn cvs ;)

It may work for older versions.

teradome’s picture

Hmm, it may just be my hosted install but I get this error:

warning: move_uploaded_file(): open_basedir restriction in effect. File(/tmp/df20060116.jpg) is not within the allowed path(s): (/home/:/usr/local/:/tmp/serversidefilter/:/var/sqmail/:/tmp/filterfile.:/mnt/paul_usb/) in /home/www/vhosts/www.wierzbowski.net/htdocs/includes/file.inc on line 144.

I'm wondering if this latest version is working for other 4.6.xers.

krichlin’s picture

I'm in this boat too. My host is a college university, and I can't get safe mode turned off. So you guys are my last and best hope for keeping drupal as our CMS!

krichlin’s picture

Well it seems to work, except my host's safe mode must be extra-safe, because it tells me

move_uploaded_file(): SAFE MODE Restriction in effect. The script whose uid is 1511512 is not allowed to access /tmp owned by uid 0 in ./includes/file.inc on line 144.

So my host won't let e use move_uploaded_file()... :(

Stefan, I don't suppose you could tell us more about that phpupload script that got you around this?

Thanks,

Ken

romca’s picture

Version: 4.6.3 » 4.6.5

Hello,
I got to exactly same issue (more, uploading of user pictures didn't work - Drupal had wrong path in the user module, not thinking that pictures should be inside files)

for me, it works in the basedir restricted environment, and should work for you to

here are the relevant function from file.inc, the point is that we use move_uploaded_file in the file_check_upload function but also the arguments being sent from other functions needed to be changed, also, you should not use FILE_DIRECTORY_TEMP because in restricted hostings it may point to /tmp (and php with open_basedir will not allow you to write there, you should use drupal's own tem pdirectory - and it must be relative):

function file_check_upload($source) {

  if (is_object($source)) {
    if (is_file($source->filepath)) {
      return $source;
    }
  } 
  elseif ($_FILES["edit"]["name"][$source] && is_uploaded_file($_FILES["edit"]["tmp_name"][$source])) {
    $drupal_temp = variable_get('file_directory_temp', FILE_DIRECTORY_TEMP);
    move_uploaded_file($_FILES["edit"]["tmp_name"][$source], $drupal_temp ."/".$_FILES["edit"]["name"][$source]);
    $file = new StdClass();
    $file->filename = trim(basename($_FILES["edit"]["name"][$source]), '.');
    $file->filemime = $_FILES["edit"]["type"][$source];
    $file->filepath = $drupal_temp ."/".$_FILES["edit"]["name"][$source]; //$_FILES["edit"]["tmp_name"][$source];
    $file->error = $_FILES["edit"]["error"][$source];
    $file->filesize = $_FILES["edit"]["size"][$source];
    $file->source = $source;
    return $file;
  }
  else {
    // In case of previews return previous file object.
    if (file_exists($_SESSION['file_uploads'][$source]->filepath)) {
      return $_SESSION['file_uploads'][$source];
    }
  }
}

function file_save_upload($source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
  // Make sure $source exists in $_FILES.
  if ($file = file_check_upload($source)) {
    if (!$dest) {
      $dest = variable_get('file_directory_temp', FILE_DIRECTORY_TEMP);
      $temporary = 1;
      if (is_file($file->filepath)) {
        // If this file was uploaded by this user before replace the temporary copy.
        $replace = 1;
      }
    }

and here are changed function user.module:

from the function user_validate_picture 

  if (!form_get_errors()) {
	if ($file = file_save_upload($file, variable_get('file_directory_path', 'files') .'/' . variable_get('user_picture_path', 'pictures') .'/picture-'. $user->uid . '.' . $info['extension'], 1)) {
      $edit['picture'] = $file->filepath;
    }
    else {
      form_set_error('picture', t("Failed to upload the picture image; the %directory directory doesn't exist.", array('%directory' => '<em>'. variable_get('user_picture_path', 'pictures') .'</em>')));
    }
  }

sorry for not sending patch, this is easier for me ;-)

hth

RonaldPagan’s picture

I am having this problem too. Does this update fix the problem? If so is there a patch? I am uncertain about pasting this code properly.

teradome’s picture

I agree with Ronald... that may have been easier for you since you have it working, but patches are easier for us. :D Considering some of these blocks are partial code, I'm hesitant to apply them as well.

I wish this would get a little more priority -- my affected site is centered on image uploading, and it's been at a standstill since November.

magico’s picture

Version: 4.6.5 » 4.6.9

Does this still deserves a patch for 4.6.9 or everyone already upgraded to 4.7?

magico’s picture

Version: 4.6.9 » 4.7.3
Status: Needs work » Active

Is this an issue in 4.7.3?

druppp’s picture

This is still an issue in 4.7.3.

Fix this please.

Hopefully within a week ;-).
When my project is due.

I've tried the cvs snapshot code but there was no database file included ...

At php.net they claim proper use of a ./tmp directory avoids uploaded files with the wrong owner.
The discussion here seems to suggest this to.

Thanks in advance.

ednique’s picture

Maybe this could help:
http://drupal.org/node/82223

magico’s picture

Title: Safe mode workaround? » Cannot upload files with PHP safe mode
Version: 4.7.3 » 5.x-dev

Confirmed. This should have high priority, but it's not so critical...

Takafumi’s picture

I think the only solution of this issue to write the following configuration directive into .htaccess or php.ini in your Drupal root directory.

php_value upload_tmp_dir  /path/to/drupaldir/tmp
Bèr Kessels’s picture

The original poster talks about files with mode 777.
I am wondering if we should bother at all about that. 777 is something that should be discouraged at all costs.

chx’s picture

Status: Active » Closed (won't fix)

Even PHP authors think safe mode is broken and it'll be removed from PHP 6. Do not use it. If your host uses it, change hosts.

Bèr Kessels’s picture

Let me add:
If your host forces you to make your /files world writable (777): switch hosts. 90% of the safe mode errors are caused because of this *way* too loose permission.