jessevl Posted February 14, 2015 Share Posted February 14, 2015 Hi there, I've been successfully using WireUpload to upload images to a temp folder and then add them to a page and subsequently remove the temp file. However, since I need to do this in a variety of different pages and multiple times on one page, I'd rather build a function for this. Somehow I cannot get this working in any way while almost the same code works fine outside of a function. Does anybody know what I'm doing wrong? WireUpload should be able to access $_FILES just fine as it is a superglobal variable, but it acts as if it isn't...I can see that nothing is uploaded to the temporary folder (I commented out the temp folder cleanup code). I found one other case of a similar problem but that was solved by directly adding the upload from the PHP tmp dir to the page (skipping wireupload altogether)... which doesn't seem right or safe to me. My code when using a function: function uploadphoto($inputname,$pagefield,$pageid){ //inputname is the input field name, pagefield is the field the image should be added to, pageid is the page it should be added to $path = $config->paths->root . 'site/assets/tmp/'; $newfilename = $pageid."_".$pagefield; //wireupload seems to add an extension by itself so no need to do that? $u = new WireUpload($inputname); $u->setMaxFiles(1); $u->setMaxFileSize(2*2048*2048); $u->setOverwrite(true); $u->setDestinationPath($path); $u->setTargetFilename($newfilename); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png')); // execute upload and check for errors foreach($u->execute() as $filename) { if(!$u->getErrors()){ // add images upload $pageid->of(false); $pageid->$pagefield->deleteAll(); // I want only 1 image $pageid->$pagefield->add($path . $filename); // save page $pageid->save(); //unlink($path . $filename); commented this out because I want to check if it uploads anything at all... and it doesn't } else { // remove files //unlink($path . $filename); commented this out because I want to check if it uploads anything at all... and it doesn't // get the errors foreach($u->getErrors() as $error) { $errors[] = $error; } return "<ul><li>" . implode("</li><li>", $errors) . "</li></ul>"; } } } $profilepicture = $_FILES['profilepicture']['name'][0]; $profilebackground = $_FILES['profilebackground']['name'][0]; if ($profilepicture) { //check if a file was uploaded uploadphoto('profilepicture','profilepicture',$editpage->id); //pass to the function } if ($profilebackground) { uploadphoto('profilebackground','profilebackground',$editpage->id); } The input field (form itself has proper encoding set): <input type='file' name='profilebackground' accept='image/jpg,image/jpeg,image/gif,image/png'/> The following code (without a function) works perfectly: $profilepicture = $_FILES['profilepicture']['name'][0]; $profilebackground = $_FILES['profilebackground']['name'][0]; if ($profilepicture) { $path = $this->config->paths->root . 'site/assets/tmp/'; $newfilename = $user->id."_profilepicture"; $u = new WireUpload('profilepicture'); $u->setMaxFiles(1); $u->setMaxFileSize(2*2048*2048); $u->setOverwrite(true); $u->setDestinationPath($path); $u->setTargetFilename($newfilename); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png')); // execute upload and check for errors foreach($u->execute() as $filename) { if(!$u->getErrors()){ // add images upload $user->of(false); $user->profilepicture->deleteAll(); $user->profilepicture->add($path . $filename); // save page $user->save(); unlink($path . $filename); } else { // remove files unlink($path . $filename); // get the errors foreach($u->getErrors() as $error) { $errors[] = $error; } $page->body .= "<ul><li>" . implode("</li><li>", $errors) . "</li></ul>"; } } } if ($profilebackground) { $path = $this->config->paths->root . 'site/assets/tmp/'; $origfilename = $_FILES['profilebackground']['name'][0]; $filenameparts = pathinfo($u); $newfilename = $user->id."_profilebackground".$filenameparts['extension']; $u = new WireUpload('profilebackground'); $u->setMaxFiles(1); $u->setMaxFileSize(2*2048*2048); $u->setOverwrite(true); $u->setDestinationPath($path); $u->setTargetFilename($newfilename); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png')); // execute upload and check for errors foreach($u->execute() as $filename) { if(!$u->getErrors()){ // add images upload $user->of(false); $user->profilebackground->deleteAll(); $user->profilebackground->add($path . $filename); // save page $user->save(); unlink($path . $filename); } else { // remove files unlink($path . $filename); // get the errors foreach($u->getErrors() as $error) { $errors[] = $error; } $page->body .= "<ul><li>" . implode("</li><li>", $errors) . "</li></ul>"; } } } Thanks in advance! Link to comment Share on other sites More sharing options...
kongondo Posted February 14, 2015 Share Posted February 14, 2015 (edited) This code will not work inside a function due to PHP variable scope. $path = $config->paths->root . 'site/assets/tmp/'; It should be like this. $path = wire('config')->paths->root . 'site/assets/tmp/'; Or even shorter... $path = wire('config')->paths->assets . 'tmp/'; If you develop with debug mode on, you will get useful feedback about where your code breaks. More tips here: https://processwire.com/talk/topic/3466-access-config-inside-function/ https://processwire.com/talk/topic/6365-how-to-use-selector-in-function/ Btw, in your 'outside function code' you are using the code below. Are you using thats in a class? Why the $this? $path = $this->config->paths->root . 'site/assets/tmp/'; Edited February 14, 2015 by kongondo 1 Link to comment Share on other sites More sharing options...
jessevl Posted February 14, 2015 Author Share Posted February 14, 2015 This code will not work inside a function due to PHP scope. $path = $config->paths->root . 'site/assets/tmp/'; It should be like this. $path = wire('config')->paths->root . 'site/assets/tmp/'; Or even shorter... wire('config')->paths->assets . 'tmp/'; If you develop with debug mode on, you will get useful feedback about where your code breaks. More tips here: https://processwire.com/talk/topic/3466-access-config-inside-function/ https://processwire.com/talk/topic/6365-how-to-use-selector-in-function/ Btw, in your 'outside function code' you are using the code below. Are you using thats in a class? Why the $this? $path = $this->config->paths->root . 'site/assets/tmp/'; Thanks a lot that's indeed it! I see I made the same mistake in the add to the page part as well, but at least that does give me error messages I can work with (and the solution is again to use wire()) About the $this part. You're right it doesn't make sense, it is what one of the examples did but I replaced it for $config later on. Link to comment Share on other sites More sharing options...
kongondo Posted February 14, 2015 Share Posted February 14, 2015 No worries. Oh, and welcome to the forums.... Link to comment Share on other sites More sharing options...
jessevl Posted February 14, 2015 Author Share Posted February 14, 2015 OK, so I now changed the function to use wire instead of the processwire variables directly. I assume wire('pages')->get($pageid) should return the object to me and allow me to add and save etc. However, I get an "Error: Exception: Can't save page 1037: /viables/view/test2/: Call $page->setOutputFormatting(false) before getting/setting values that will be modified and saved. [profilepicture]". It seems to me like I disabled output formatting already but apparently I cannot do that in this way? function uploadphoto($inputname,$pagefield,$pageid){ $path = wire('config')->paths->assets . 'tmp/'; $newfilename = $pageid."_".$pagefield; $u = new WireUpload($inputname); $u->setMaxFiles(1); $u->setMaxFileSize(2*2048*2048); $u->setOverwrite(true); $u->setDestinationPath($path); $u->setTargetFilename($newfilename); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png')); // execute upload and check for errors foreach($u->execute() as $filename) { if(!$u->getErrors()){ // add images upload wire('pages')->get($pageid)->of(false); wire('pages')->get($pageid)->$pagefield->deleteAll(); wire('pages')->get($pageid)->$pagefield->add($path . $filename); // save page wire('pages')->get($pageid)->save(); //unlink($path . $filename); } else { // remove files //unlink($path . $filename); // get the errors foreach($u->getErrors() as $error) { $errors[] = $error; } return "<ul><li>" . implode("</li><li>", $errors) . "</li></ul>"; } } } $profilepicture = $_FILES['profilepicture']['name'][0]; $profilebackground = $_FILES['profilebackground']['name'][0]; if ($profilepicture) { uploadphoto('profilepicture','profilepicture',$editpage->id); } if ($profilebackground) { uploadphoto('profilebackground','profilebackground',$editpage->id); } Link to comment Share on other sites More sharing options...
kongondo Posted February 14, 2015 Share Posted February 14, 2015 You add images code does not look OK. If you had debug on you should get an error round about here I think. wire('pages')->get($pageid)->$pagefield->deleteAll(); Because of this: wire('pages')->get($pageid)->of(false); You only need to call the page you want once. Try this instead: $p = wire('pages')->get($pageid) $p->of(false); $p->$pagefield->deleteAll(); $p->$pagefield->add($path . $filename); // save page $p->save();//maybe even saving $pagefield only would work...rather than the whole page Link to comment Share on other sites More sharing options...
jessevl Posted February 15, 2015 Author Share Posted February 15, 2015 That works. But I don't think I fully understand why that makes a difference (although it's clear that it does). I'm assuming it's actually a PHP thing and not Processwire specific, any hint on what keyword to search for to better understand how this works? Thanks for the help, really appreciate it. Link to comment Share on other sites More sharing options...
kongondo Posted February 15, 2015 Share Posted February 15, 2015 The 'keyword' to search for is PHP Object Oriented Programming (OOP). Find a good tutorial about OOP Classes, Objects, Methods (functions) and Properties (variables). A ProcessWire $page is an 'instance', i.e. and Object of the Class Page (see /wire/core/Page.php). In OOP, you can call/access the members of a Class (Methods and Properties) by 'creating' an instance/Object of that Class. When you use the variable $page, behind the scenes you are actually creating an instance of the class, i.e. $p = new Page(); You can create as many Objects of that Class as you want. The key here is that they will all be tracked differently by PHP - they are independent Objects of the same Class. So, in your case although your wire('pages')->get($pageid) were, from a database point of view, all grabbing the same page, from a OOP point of view, they were all different Objects, tracked differently, i.e. you were doing $x = new Page(), $y = new Page(), etc. Also, this should not work wire('pages')->get($pageid)->of(false); - since you need to get the page first (I could be wrong here) - and even if it did, it was a 'different' Object to the $page in the next line wire('pages')->get($pageid)->$pagefield->deleteAll(); So, in order to tell PHP that you were talking about a specific/single Object, we assign the $page we are after to the variable $p (behind the scenes $p = new Page(); - but not just any Page, but one with the id $p->id=1234 (from the wire('pages')->get(1234). Written late, I could have missed something but hope this makes sense.... 3 Link to comment Share on other sites More sharing options...
jessevl Posted February 15, 2015 Author Share Posted February 15, 2015 The 'keyword' to search for is PHP Object Oriented Programming (OOP). Find a good tutorial about OOP Classes, Objects, Methods (functions) and Properties (variables). A ProcessWire $page is an 'instance', i.e. and Object of the Class Page (see /wire/core/Page.php). In OOP, you can call/access the members of a Class (Methods and Properties) by 'creating' an instance/Object of that Class. When you use the variable $page, behind the scenes you are actually creating an instance of the class, i.e. $p = new Page(); You can create as many Objects of that Class as you want. The key here is that they will all be tracked differently by PHP - they are independent Objects of the same Class. So, in your case although your wire('pages')->get($pageid) were, from a database point of view, all grabbing the same page, from a OOP point of view, they were all different Objects, tracked differently, i.e. you were doing $x = new Page(), $y = new Page(), etc. Also, this should not work wire('pages')->get($pageid)->of(false); - since you need to get the page first (I could be wrong here) - and even if it did, it was a 'different' Object to the $page in the next line wire('pages')->get($pageid)->$pagefield->deleteAll(); So, in order to tell PHP that you were talking about a specific/single Object, we assign the $page we are after to the variable $p (behind the scenes $p = new Page(); - but not just any Page, but one with the id $p->id=1234 (from the wire('pages')->get(1234). Written late, I could have missed something but hope this makes sense.... Thanks for the awesome explanation! Yes I think I fully understand now. I was just setting the OF to false on one instance of the page, writing the image to another instance of the page, and saving yet another (unchanged, non-of'ed) instance of the page... (which failed because OF was not set to false on that specific instance). 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now