3

Context: we sell some magazines and other newspapers on our site, and updating all the cover images manually is a hassle.

I would like the ability to write a url in a field (www.myimageprovider.com/product1) and set a cron job to fetch any new images for the day, for that specific product, and update the entry with the new image.

I'm having a hard time figuring out how to "fake" a file upload from a craft controller/service, as if it was uploaded from the CP form. I have tried something like this:

$file = array();
$url = $entry->getFieldValue('imagefetchurl'); // somegoogleimageurl.com/image.png
$tmpfname = tempnam("/tmp", "UL_IMAGE");
$img = file_get_contents($url);
file_put_contents($tmpfname, $img);
$file['size'] = filesize($tmpfname); // 245 kB
$file['name'] = basename($url); // image.png
$file['tmp_name'] = $tmpfname; // C:\\Windows\\Temp\\UL_XXXX.tmp

$_FILES['assets-upload'] = $file;
$assetOperationResponseModel = craft()->assets->uploadFile(1);

This throws an error

PHP notice

getimagesize(): Read error! - in ...craft\app\services\ImagesService.php(114)

I can see that the image get downloaded, the size and name is correct.

Any pointers and ideas are greatly appreciated

EDIT

After some digging, looks like i have to write my own upload handler for this task. http://www.1-script.com/forums/php/simulate-file-upload-so-that-move-uploaded-file-succeeds-124012-.htm

Basically not possible unless you change the PHP source

I suppose i could override the function, but my instinct tells me that's a bad idea. I will have to go with an alternative approach

  • 1
    Very strange. First thing I'd do is go to that line (114) and dump the $filePath variable, exit, and check to see if the file exists in that location, if you haven't done so already. – Ben Fleming Jul 23 '15 at 11:19
  • @Benjammin' thank you, that got me going! Turns out craft uses move_uploaded_file() to move the file to its own internal temp storage. If I change move_uploaded_file() to copy() it works. Maybe if i set some $_POST variables it will work? – fuling Jul 23 '15 at 11:40
  • No worries, shame it wasn't easier to fix. I've built a plugin recently that upload images into the asset manager and my solution was to essentially copy the BaseAssetSourceType::uploadFile() method to my controller and tweak it to my needs. Hope you can get it working! – Ben Fleming Jul 23 '15 at 12:14
3

Answering my own question for reference.

I was tunneling too hard on the PHP, a simple bash script takes care of the upload.

# assuming the image is already downloaded and no CP-login required
curl -F assets-upload=@/path/to/image mycraftsite/admin/actions/assets/uploadFile

EDIT

Better answer: Thanks to this answer I discovered the insertFileByLocalPath() function in AssetsService.

  $entry = craft()->entries->getEntryById($id);
  if($entry && isset($entry["imageFetchUrl"])) {
    $url = $entry->getFieldValue("imageFetchUrl");
    $tmpfname = tempnam("/tmp", "UL_IMAGE");
    $img = file_get_contents($url);
    file_put_contents($tmpfname, $img);
    craft()->assets->insertFileByLocalPath($tmpfname, 'fetchedImg.jpg', $myFolderId);
  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.