Jump to content

Error saving file coming from Pagefile (kinda urgent)


evanmcd
 Share

Recommended Posts

Hi all,

I've just discovered an error on a LIVE site.  I'm uploading images, then adding the already uploaded image to a Page

The file gets uploaded first into the root of file, then the user submits a form with the file name in entry_photo

$entry->entry_photo = $config->paths->files . '/' . $input->post["entry_photo"];
$entry_result = $entry->save();

Gets me this error:

Error: Exception: Unable to copy: /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/site/assets/files//19feeda0a3882049c8815a9d69d7ef2d_cute-dog-dogs-13286656-1024-768.jpg => /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/site/assets/files/38361/19feeda0a3882049c8815a9d69d7ef2d_cute-dog-dogs-13286656-1024-768.jpg (in /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Pagefile.php line 109)

#0 [internal function]: Pagefile->___install('/var/www/vhosts...')
#1 /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Wire.php(271): call_user_func_array(Array, Array)
#2 /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Wire.php(229): Wire->runHooks('install', Array)
#3 /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Pagefile.php(74): Wire->__call('install', Array)
#4 /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Pagefile.php(74): Pageimage->inst

I'm running php 5.2.17 if that makes a difference, and yes the Page file folders are set to 777  Thanks for any help anyone could offer ( I could REALLY use it)

Link to comment
Share on other sites

Yeah, sorry, I've found that the trailing slash after the config URL doesn't matter.  Just removed it and get the same error but without the two slashes:

Error: Exception: Unable to copy: /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/site/assets/files/19feeda0a3882049c8815a9d69d7ef2d_cute-dog-dogs-13286656-1024-768.jpg => /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/site/assets/files/38365/19feeda0a3882049c8815a9d69d7ef2d_cute-dog-dogs-13286656-1024-768.jpg (in /var/www/vhosts/straighttalkswitch.com/httpdocs/switch-it-to-win-it/wire/core/Pagefile.php line 109)

Link to comment
Share on other sites

Based on the error, I don't see it making any difference at all, because it is a filesystem error, but I have always uploaded photos like so:

$entry->entry_photo->add($config->paths->files . $input->post["entry_photo"]);

I am sure you have entry_photo set to only support 1 image, but maybe there is something related to that, due to the way it will still be an array via the API.

I might be totally off the plot here, but when you're in a hurry to get a live site working again, sometimes it is worth trying anything :)

Link to comment
Share on other sites

OK, so I've been battling with this for a bit, but have made some progress.  The server I'm deploying to doesn't have allow_fopen_url enabled, causing the copy function to fail.

So, I've been trying to add a safe copy method to Pagefile.php

Below is my attempt so far.  Unfortunately, it fails to write the file each time.  Though of course I put a workaround in place, so that the site isn't erroring, the images are getting saved where I need them to be to display them.

protected function ___install($filename) {
		$basename = $this->pagefiles->cleanBasename($filename, true); 
		$pathInfo = pathinfo($basename); 
		$basename = basename($basename, ".$pathInfo[extension]"); 

		// remove any extra dots in the filename
		$basename = str_replace(".", "_", $basename); 
		$basenameNoExt = $basename; 
		$basename .= ".$pathInfo[extension]"; 

		// ensure filename is unique
		$cnt = 0; 
		while(file_exists($this->pagefiles->path() . $basename)) {
			$cnt++;
			$basename = "$basenameNoExt-$cnt.$pathInfo[extension]";
		}

		if(strpos($filename, ' ') !== false && strpos($filename, '://') !== false) $filename = str_replace(' ', '%20', trim($filename)); // per Pete
		$destination = $this->pagefiles->path() . $basename;
		
		try {
			$this->safe_copy_file($filename, $destination);
		} catch(WireException $ex) {
			echo($ex->getMessage());
		}
		if($this->config->chmodFile) chmod($this->pagefiles->path() . $basename, octdec($this->config->chmodFile));
		parent::set('basename', $basename); 
			
	}

	/**
	 * Manages file copies in the case when copy is not available.  
	 *
	 * Normally this is the case because all_url_fopen is set to false in php.ini
	 *
	 * @param string $source Full source path and filename of file to copy
	 * @param string $destination Full destinate path and filename of file to copy
	 *
	 */
	protected function safe_copy_file($source, $destination) {
	  $resource = curl_init();

	  $source = str_replace("/var/www/vhosts/straighttalkswitch.com/httpdocs", "https://www.straighttalkswitch.com", $source);
	 
	  	curl_setopt($resource, CURLOPT_URL, $source);
	  	curl_setopt($resource, CURLOPT_HEADER, 0);
	  	curl_setopt($resource, CURLOPT_BINARYTRANSFER, 1);
		curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($resource, CURLOPT_CONNECTTIMEOUT, 30);
		curl_setopt($resource, CURLOPT_SSL_VERIFYHOST, 0);
		curl_setopt($resource, CURLOPT_SSL_VERIFYPEER, 0);
	 
	  $content = curl_exec($resource);
	 
	  curl_close($resource);

	  if($content != '') {

	    $fp = fopen($destination, 'wb');
	    $fw = fwrite($fp, $content);
	    fclose($fp);
	 
	    if($fw != false) {
	      return true;
	    } else {
	    	throw new WireException("Error: file write failed.  Source: " .$source . "; Destination: " . $destination);	
	    }
	  } else {
	  	throw new WireException("Error: curl_exec failed to gather the resource");
	  }
	 
	  return false;
	}

I was able to get the file to save by just putting this code in a template and running it directly

$resource = curl_init();
curl_setopt($resource, CURLOPT_URL, 'https://www.straighttalkswitch.com/switch-it-to-win-it/site/assets/files/34d50563316208286b56a1564b1082ba_cute-dog-dogs-13286656-1024-768.jpg');
curl_setopt($resource, CURLOPT_HEADER, 0);
curl_setopt($resource, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($resource, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($resource, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($resource, CURLOPT_SSL_VERIFYPEER, 0);

$content = curl_exec($resource);

curl_close($resource);

if($content != '') {
	$fp = fopen($config->paths->files . 'test/34d50563316208286b56a1564b1082ba_cute-dog-dogs-13286656-1024-768.jpg', 'wb');
	$fw = fwrite($fp, $content);
	fclose($fp);
	header('Content-type: image/jpeg');
	echo($content);

} else {
	echo("failed to save");
}

Thanks to anyone who can help.

Link to comment
Share on other sites

I am confused - something that seems to be happening a lot lately :), but why does a local file copy need allow_fopen_url? What am I missing? Is it something to do with the fact that you are setting the source to https://..... rather than just the full path? The original error message doesn't seem to show this though?

Sorry, probably not much help - I will bow out now :)

Link to comment
Share on other sites

I always thouht allow url fopen is only needed when getting a file from external url and not local server path. Isn't it? When I turn off allow_url_fopen I still can add a image from assets/files/ to a page.

Link to comment
Share on other sites

Mystery solved.  It seems that the php config for this server had php safe_mode on.  Safe mode is deprecated in 5.3 and removed in 5.4 but I'm on 5.2.17, so it was on.

Turn safe mode off and all is well again.

Thanks for your effort guys.  Hopefully this post can help someone out in the future.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...